Merge branch 'efroemling:main' into main

This commit is contained in:
Vishal 2024-09-05 00:39:04 +05:30 committed by GitHub
commit fa7fd72e57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 353 additions and 516 deletions

56
.efrocachemap generated
View File

@ -4096,26 +4096,26 @@
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "a0e1890fc3d156a1d480e7cbba7295bd", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "fa2f9a37401974a330f6406bfdde195a",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "2ea3ddfd5280b5fa721a82286767208a", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "ec0ca83cb8d63837d86024926a9f5792",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f9860dbec27801cf8b24c3b42e0b62bd", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "22e11f5d894e02b521f1c77a3b1d14ad",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "a53de05a4a3c3c2e766f488b0b53230d", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "803d4449de9e62bc33d62edaccb3a40c",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "43485a1c27605267ee83d27961b61017", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "5ee49f99993e6f690c955bf4e22ea232",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "65fe6d346dfd844925a07278a73bbb39", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "f6882aef1cf0c4ab6a4d71b19e048ea3",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "bc277e964bc08d0bd086f836732901f8", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "2de6855febbe3fefbd1a696e54ff198c",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "738e76cf0dc643a016f16f94503767db", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "76fff0d53458ff9308ee9050bfe42321",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "949fd54340bc597c19ada580f59c30a9", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "4b0f3502089e9a7ea6ea2db0c44ecee9",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "f0f1037044f841e6817e970ba67f3c02", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "d426ae451363579868ed80e070ee1a7d",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "3990893e788968fe74e98aa419f28397", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "147e64e814f72846d5f78944df85f879",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "0c5fbd4cd45f944f02d7482e08d4b5d5", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "0e28cef28d1097cd61c1faa2f18b900d",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "c39bcf72ef41865429f3df1d3ad586d0", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "213712de0e2e9c5fcbaf9b2cebd92ff7",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "37cb193fec5c61443fafa24d3ae96447", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "34122e2302160ce65f4ac624e6b40876",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "e454f30500a3ef2c0e4248388338db89", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "09f8466080d70d84c15d697a659c6561",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "ddb81916ad653ccb38be9ffc9f98e7f3", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "ad91f8448f3106a7d81f2615ab82d71c",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "18766baaa9e1a23e785aceb9f6be0d3a", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "6a369680967a22140b9a5d3dd65cfd65",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "b687f66795a831f0dfd7e15aa7a908b2", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "eb2ccde783e4e7abaf40a76ed0be4a0c",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "146168838c8e9cdbd5c016772b68e91a", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "112881e2d4429018dc5487a979d53a80",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f0ee92768afe3211aeab356539d58876", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "04b1f16241efd35e95ff544de09f3444",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c", "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_gui/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c",
@ -4132,14 +4132,14 @@
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e", "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/debug/libballisticaplus.a": "1659535e95e3047fda529543e265ac97",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "07c51c6015b17d6ad2e32ac6bad9aaee", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "599167b1b452e9a060475c059ebb742e",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "d9dc89c65a1f5ae3a0a4e25636129bb7", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "4495e25c4e6e286ebe0ac547c3c785e5",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "8afac2e5edb1586137c60ce1d4829d0a", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "ee961522b1a726d982df90d35178f4df",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "c9bfc854e52b6d2270d748ce80f45342", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "de121ab71098df1ff6a9b72b46c30401",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "ec65affda58721c395d5188810195443", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "6319a5f16af08ad8cd396472e623b4e1",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "e16447cfaffecc545ae970aff2f09d16", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "1464b16e286fc6379aa6e9d8d7b7ddaa",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "1f5ba81d75d56eb680bb7f3aefaae5b6", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "64c3bce65d48d16c7b0f5f59105a8856",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "44bc0d1aab93081db335ebd837f44632", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a10c2110bb0155790ddc49a44388ba4c",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6", "src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d", "src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",

View File

@ -1,4 +1,4 @@
### 1.7.37 (build 21985, api 9, 2024-09-03) ### 1.7.37 (build 21986, api 9, 2024-09-04)
- Bumping api version to 9. As you'll see below, there's some UI changes that - 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 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. touch UI stuff at all you can simply bump your api version and call it a day.

View File

@ -135,14 +135,19 @@ class ClassicAppMode(AppMode):
# Blow away the window stack and build a fresh one. # Blow away the window stack and build a fresh one.
ui.clear_main_window() ui.clear_main_window()
back_state = (
MainMenuWindow.do_get_main_window_state()
if in_main_menu()
else InGameMenuWindow.do_get_main_window_state()
)
# set_main_window() needs this to be set.
back_state.is_top_level = True
ui.set_main_window( ui.set_main_window(
window, window,
from_window=False, # Disable from-check. from_window=False, # Disable from-check.
back_state=( back_state=back_state,
MainMenuWindow.do_get_main_window_state() suppress_warning=True,
if in_main_menu()
else InGameMenuWindow.do_get_main_window_state()
),
) )
def _root_ui_menu_press(self) -> None: def _root_ui_menu_press(self) -> None:

View File

@ -735,15 +735,30 @@ class ClassicAppSubsystem(babase.AppSubsystem):
def profile_browser_window( def profile_browser_window(
self, self,
transition: str = 'in_right', transition: str = 'in_right',
in_main_menu: bool = True,
selected_profile: str | None = None,
origin_widget: bauiv1.Widget | None = None, origin_widget: bauiv1.Widget | None = None,
# in_main_menu: bool = True,
selected_profile: str | None = None,
) -> None: ) -> None:
"""(internal)""" """(internal)"""
from bauiv1lib.profile.browser import ProfileBrowserWindow from bauiv1lib.profile.browser import ProfileBrowserWindow
ProfileBrowserWindow( main_window = babase.app.ui_v1.get_main_window()
transition, in_main_menu, selected_profile, origin_widget if main_window is not None:
logging.warning(
'profile_browser_window()'
' called with existing main window; should not happen.'
)
return
babase.app.ui_v1.set_main_window(
ProfileBrowserWindow(
transition=transition,
selected_profile=selected_profile,
origin_widget=origin_widget,
minimal_toolbar=True,
),
is_top_level=True,
suppress_warning=True,
) )
def preload_map_preview_media(self) -> None: def preload_map_preview_media(self) -> None:
@ -799,9 +814,7 @@ class ClassicAppSubsystem(babase.AppSubsystem):
bauiv1.getsound('swish').play() bauiv1.getsound('swish').play()
babase.app.ui_v1.set_main_window( babase.app.ui_v1.set_main_window(
InGameMenuWindow(), InGameMenuWindow(), is_top_level=True, suppress_warning=True
from_window=False, # Disable check here.
is_top_level=True,
) )
def invoke_main_menu_ui(self) -> None: def invoke_main_menu_ui(self) -> None:
@ -896,8 +909,8 @@ class ClassicAppSubsystem(babase.AppSubsystem):
app.ui_v1.set_main_window( app.ui_v1.set_main_window(
MainMenuWindow(transition=None), MainMenuWindow(transition=None),
from_window=False, # Disable check.
is_top_level=True, is_top_level=True,
suppress_warning=True,
) )
# attempt to show any pending offers immediately. # attempt to show any pending offers immediately.

View File

@ -52,7 +52,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be # Build number and version of the ballistica binary we expect to be
# using. # using.
TARGET_BALLISTICA_BUILD = 21985 TARGET_BALLISTICA_BUILD = 21986
TARGET_BALLISTICA_VERSION = '1.7.37' TARGET_BALLISTICA_VERSION = '1.7.37'

View File

@ -588,10 +588,16 @@ class Chooser:
# Handle '_edit' as a special case. # Handle '_edit' as a special case.
if profilename == '_edit' and ready: if profilename == '_edit' and ready:
with babase.ContextRef.empty(): with babase.ContextRef.empty():
classic.profile_browser_window(in_main_menu=False) # if bool(True):
# babase.screenmessage('UNDER CONSTRUCTION')
# return
# Give their input-device UI ownership too classic.profile_browser_window(
# (prevent someone else from snatching it in crowded games) # in_main_menu=False
)
# Give their input-device UI ownership too (prevent
# someone else from snatching it in crowded games).
babase.set_ui_input_device(self._sessionplayer.inputdevice.id) babase.set_ui_input_device(self._sessionplayer.inputdevice.id)
return return

View File

@ -7,6 +7,7 @@ from __future__ import annotations
import logging import logging
import inspect import inspect
import weakref import weakref
import warnings
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING, override from typing import TYPE_CHECKING, override
@ -162,10 +163,16 @@ class UIV1AppSubsystem(babase.AppSubsystem):
# 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) self.upkeeptimer = babase.AppTimer(2.6543, ui_upkeep, repeat=True)
def do_main_window_back(self, from_window: MainWindow) -> None: def auto_set_back_window(self, from_window: MainWindow) -> None:
"""Sets the main menu window automatically from a parent WindowState.""" """Sets the main menu window automatically from a parent WindowState."""
main_window = self._main_window() main_window = self._main_window()
# This should never get called for top-level main-windows.
assert (
main_window is None or main_window.main_window_is_top_level is False
)
back_state = ( back_state = (
None if main_window is None else main_window.main_window_back_state None if main_window is None else main_window.main_window_back_state
) )
@ -175,8 +182,17 @@ class UIV1AppSubsystem(babase.AppSubsystem):
f' cannot use auto-back.' f' cannot use auto-back.'
) )
backwin = back_state.create_window(transition='in_left') backwin = back_state.create_window(transition='in_left')
backwin.main_window_back_state = back_state.parent
self.set_main_window(backwin, from_window=from_window, is_back=True) # Properly created state should have a value here.
assert back_state.is_top_level is not None
self.set_main_window(
backwin,
from_window=from_window,
is_back=True,
back_state=back_state,
suppress_warning=True,
)
def get_main_window(self) -> bauiv1.MainWindow | None: def get_main_window(self) -> bauiv1.MainWindow | None:
"""Return main window, if any.""" """Return main window, if any."""
@ -189,6 +205,7 @@ class UIV1AppSubsystem(babase.AppSubsystem):
is_back: bool = False, is_back: bool = False,
is_top_level: bool = False, is_top_level: bool = False,
back_state: MainWindowState | None = None, back_state: MainWindowState | None = None,
suppress_warning: bool = False,
) -> None: ) -> None:
"""Set the current 'main' window, replacing any existing. """Set the current 'main' window, replacing any existing.
@ -201,7 +218,17 @@ class UIV1AppSubsystem(babase.AppSubsystem):
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
from bauiv1._uitypes import MainWindow from bauiv1._uitypes import MainWindow
from_window_widget: bauiv1.Widget | None # Encourage migration to the new higher level nav calls.
if not suppress_warning:
warnings.warn(
'set_main_window() should usually not be called directly;'
' use the main_window_replace() or main_window_back()'
' methods on MainWindow objects for navigation instead.'
' If you truly need to use set_main_window(),'
' pass suppress_warning=True to silence this warning.',
DeprecationWarning,
stacklevel=2,
)
# We used to accept Widgets but now want MainWindows. # We used to accept Widgets but now want MainWindows.
if not isinstance(window, MainWindow): if not isinstance(window, MainWindow):
@ -213,7 +240,8 @@ class UIV1AppSubsystem(babase.AppSubsystem):
window_widget = window.get_root_widget() window_widget = window.get_root_widget()
if isinstance(from_window, MainWindow): if isinstance(from_window, MainWindow):
from_window_widget = from_window.get_root_widget() # from_window_widget = from_window.get_root_widget()
pass
else: else:
if from_window is not None and not isinstance(from_window, bool): if from_window is not None and not isinstance(from_window, bool):
raise RuntimeError( raise RuntimeError(
@ -222,110 +250,93 @@ class UIV1AppSubsystem(babase.AppSubsystem):
f' You passed a {type(from_window)}.', f' You passed a {type(from_window)}.',
) )
from_window_widget = None existing = self._main_window()
existing = self._main_window_widget # If they passed a back-state, make sure it is fully filled out.
if back_state is not None:
try: if back_state.is_top_level is None:
if isinstance(from_window, bool): raise RuntimeError(
# For default val True we warn that the arg wasn't 'back_state.is_top_level has not been set.'
# passed. False can be explicitly passed to disable this ' Make sure to only pass fully-filled-out MainWindowStates.'
# check.
if from_window is True:
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_line_number = caller_frame.lineno
logging.warning(
'set_main_window() should be passed a'
" 'from_window' value to help ensure proper UI behavior"
' (%s line %i).',
caller_filename,
caller_line_number,
)
else:
# For everything else, warn if what they passed wasn't
# the previous main menu widget.
if from_window_widget is not existing:
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_line_number = caller_frame.lineno
logging.warning(
"set_main_window() was passed 'from_window' %s"
' but existing main-menu-window is %s. (%s line %i).',
from_window_widget,
existing,
caller_filename,
caller_line_number,
)
except Exception:
# Prevent any bugs in these checks from causing problems.
logging.exception('Error checking from_window')
# Once the above code leads to us fixing all leftover window
# bugs at the source, we can kill the code below.
# Let's grab the location where we were called from to report if
# we have to force-kill the existing window (which normally
# should not happen).
frameline = None
try:
frame = inspect.currentframe()
if frame is not None:
frame = frame.f_back
if frame is not None:
frameinfo = inspect.getframeinfo(frame)
frameline = f'{frameinfo.filename} {frameinfo.lineno}'
except Exception:
logging.exception('Error calcing line for set_main_window')
# NOTE: disabling this for now since hopefully our new system
# will be bulletproof enough to avoid this. Can turn it back on
# if that's not the case.
# With our legacy main-menu system, the caller is responsible
# for clearing out the old main menu window when assigning the
# new. However there are corner cases where that doesn't happen
# and we get old windows stuck under the new main one. So let's
# guard against that. However, we can't simply delete the
# existing main window when a new one is assigned because the
# user may transition the old out *after* the assignment. Sigh.
# So, as a happy medium, let's check in on the old after a short
# bit of time and kill it if its still alive. That will be a bit
# ugly on screen but at least should un-break things.
def _delay_kill() -> None:
import time
if existing:
print(
f'Killing old main_menu_window'
f' when called at: {frameline} t={time.time():.3f}'
) )
existing.delete() # If a top-level main-window is being set, complain if there already
# is a main-window.
if bool(False): if is_top_level:
babase.apptimer(1.0, _delay_kill) if existing:
logging.warning(
'set_main_window() called with top-level window %s'
' but found existing main-window %s.',
window,
existing,
)
else:
# In other cases, sanity-check that the window ordering this
# switch is the one we're switching away from.
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.
if from_window is True:
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_line_number = caller_frame.lineno
logging.warning(
'set_main_window() should be passed a'
" 'from_window' value to help ensure proper"
' UI behavior (%s line %i).',
caller_filename,
caller_line_number,
)
else:
# 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
caller_line_number = caller_frame.lineno
logging.warning(
"set_main_window() was passed 'from_window' %s"
' but existing main-menu-window is %s.'
' (%s line %i).',
from_window,
existing,
caller_filename,
caller_line_number,
)
except Exception:
# Prevent any bugs in these checks from causing problems.
logging.exception('Error checking from_window')
if is_back: if is_back:
pass # is_top_level should never be True here (only applies forward).
assert not is_top_level
# Always should have back_state in this case.
assert back_state is not None
assert back_state.is_top_level is not None
window.main_window_back_state = back_state.parent
window.main_window_is_top_level = back_state.is_top_level
else: else:
# Store if the window is top-level so we won't complain later if
# we go back from it and there's nowhere to go to.
window.main_window_is_top_level = is_top_level
# When navigating forward, generate a back-window-state from # When navigating forward, generate a back-window-state from
# the outgoing window. # the outgoing window.
if is_top_level: if is_top_level:
# Top level windows don't have or expect anywhere to # Top level windows don't have or expect anywhere to
# go back to. # go back to.
#
# self._main_window_back_state = None
window.main_window_back_state = None window.main_window_back_state = None
elif back_state is not None: elif back_state is not None:
window.main_window_back_state = back_state window.main_window_back_state = back_state
else: else:
oldwin = self._main_window() oldwin = self._main_window()
if oldwin is None: if oldwin is None:
# We currenty only hold weak refs to windows so # We currenty only hold weak refs to windows so that
# that they are free to die on their own, but we # they are free to die on their own, but we expect
# expect the main menu window to keep itself # the main menu window to keep itself alive as long
# alive as long as its the main one. Holler if # as its the main one. Holler if that seems to not
# that seems to not be happening. # be happening.
logging.warning( logging.warning(
'set_main_window: No old MainWindow found' 'set_main_window: No old MainWindow found'
' and is_top_level is False;' ' and is_top_level is False;'
@ -335,8 +346,9 @@ class UIV1AppSubsystem(babase.AppSubsystem):
else: else:
oldwinstate = oldwin.get_main_window_state() oldwinstate = oldwin.get_main_window_state()
# Store our previous back state on this new one. # Store some common window stuff on its state.
oldwinstate.parent = oldwin.main_window_back_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 = oldwinstate
self._main_window = window_weakref self._main_window = window_weakref

View File

@ -63,6 +63,8 @@ class MainWindow(Window):
# A back-state supplied by the ui system. # A back-state supplied by the ui system.
self.main_window_back_state: MainWindowState | None = None self.main_window_back_state: MainWindowState | None = None
self.main_window_is_top_level: bool = False
self._main_window_transition = transition self._main_window_transition = transition
self._main_window_origin_widget = origin_widget self._main_window_origin_widget = origin_widget
super().__init__(root_widget, cleanupcheck) super().__init__(root_widget, cleanupcheck)
@ -131,8 +133,10 @@ class MainWindow(Window):
if not self.main_window_has_control(): if not self.main_window_has_control():
return return
# Get the 'back' window coming in. if not self.main_window_is_top_level:
babase.app.ui_v1.do_main_window_back(self)
# Get the 'back' window coming in.
babase.app.ui_v1.auto_set_back_window(self)
self.main_window_close() self.main_window_close()
@ -164,7 +168,10 @@ class MainWindow(Window):
_bauiv1.containerwidget(edit=self._root_widget, transition=transition) _bauiv1.containerwidget(edit=self._root_widget, transition=transition)
babase.app.ui_v1.set_main_window( babase.app.ui_v1.set_main_window(
new_window, from_window=self, back_state=back_state new_window,
from_window=self,
back_state=back_state,
suppress_warning=True,
) )
def on_main_window_close(self) -> None: def on_main_window_close(self) -> None:
@ -186,9 +193,10 @@ class MainWindowState:
purposes, when switching app-modes, etc. purposes, when switching app-modes, etc.
""" """
def __init__(self, parent: MainWindowState | None = None) -> None: def __init__(self) -> None:
# The window that back/cancel navigation should take us to. # The window that back/cancel navigation should take us to.
self.parent = parent self.parent: MainWindowState | None = None
self.is_top_level: bool | None = None
def create_window( def create_window(
self, self,

View File

@ -14,6 +14,18 @@ if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
class CharacterPickerDelegate:
"""Delegate for character-picker."""
def on_character_picker_pick(self, character: str) -> None:
"""Called when a character is selected."""
raise NotImplementedError()
def on_character_picker_get_more_press(self) -> None:
"""Called when the 'get more characters' button is pressed."""
raise NotImplementedError()
class CharacterPicker(PopupWindow): class CharacterPicker(PopupWindow):
"""Popup window for selecting characters.""" """Popup window for selecting characters."""
@ -21,7 +33,7 @@ class CharacterPicker(PopupWindow):
self, self,
parent: bui.Widget, parent: bui.Widget,
position: tuple[float, float] = (0.0, 0.0), position: tuple[float, float] = (0.0, 0.0),
delegate: Any = None, delegate: CharacterPickerDelegate | None = None,
scale: float | None = None, scale: float | None = None,
offset: tuple[float, float] = (0.0, 0.0), offset: tuple[float, float] = (0.0, 0.0),
tint_color: Sequence[float] = (1.0, 1.0, 1.0), tint_color: Sequence[float] = (1.0, 1.0, 1.0),
@ -191,10 +203,14 @@ class CharacterPicker(PopupWindow):
show_sign_in_prompt() show_sign_in_prompt()
return return
bui.screenmessage('UNDER CONSTRUCTION') if self._delegate is not None:
return self._delegate.on_character_picker_get_more_press()
self._transition_out()
# bui.screenmessage('UNDER CONSTRUCTION')
# return
# self._transition_out()
# StoreBrowserWindow( # StoreBrowserWindow(
# modal=True, # modal=True,
# show_tab=StoreBrowserWindow.TabID.CHARACTERS, # show_tab=StoreBrowserWindow.TabID.CHARACTERS,

View File

@ -580,11 +580,9 @@ class PlayWindow(bui.MainWindow):
if plus.get_v1_account_state() != 'signed_in': if plus.get_v1_account_state() != 'signed_in':
show_sign_in_prompt() show_sign_in_prompt()
return return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left') self.main_window_replace(
assert bui.app.classic is not None CoopBrowserWindow(origin_widget=self._coop_button)
bui.app.ui_v1.set_main_window(
CoopBrowserWindow(origin_widget=self._coop_button), from_window=self
) )
def _team_tourney(self) -> None: def _team_tourney(self) -> None:
@ -595,8 +593,6 @@ class PlayWindow(bui.MainWindow):
if not self.main_window_has_control(): if not self.main_window_has_control():
return return
self._save_state()
self.main_window_replace( self.main_window_replace(
PlaylistBrowserWindow( PlaylistBrowserWindow(
origin_widget=self._teams_button, origin_widget=self._teams_button,
@ -613,16 +609,12 @@ class PlayWindow(bui.MainWindow):
if not self.main_window_has_control(): if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
PlaylistBrowserWindow( PlaylistBrowserWindow(
origin_widget=self._free_for_all_button, origin_widget=self._free_for_all_button,
sessiontype=bs.FreeForAllSession, sessiontype=bs.FreeForAllSession,
playlist_select_context=self._playlist_select_context, playlist_select_context=self._playlist_select_context,
), )
from_window=self,
) )
def _draw_dude( def _draw_dude(

View File

@ -20,16 +20,13 @@ class ProfileBrowserWindow(bui.MainWindow):
def __init__( def __init__(
self, self,
transition: str | None = 'in_right', transition: str | None = 'in_right',
in_main_menu: bool = True, # in_main_menu: bool = True,
selected_profile: str | None = None, selected_profile: str | None = None,
origin_widget: bui.Widget | None = None, origin_widget: bui.Widget | None = None,
minimal_toolbar: bool = False,
): ):
# pylint: disable=too-many-statements self._minimal_toolbar = minimal_toolbar
self._in_main_menu = in_main_menu back_label = bui.Lstr(resource='backText')
if self._in_main_menu:
back_label = bui.Lstr(resource='backText')
else:
back_label = bui.Lstr(resource='doneText')
assert bui.app.classic is not None assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale uiscale = bui.app.ui_v1.uiscale
self._width = 800.0 if uiscale is bui.UIScale.SMALL else 600.0 self._width = 800.0 if uiscale is bui.UIScale.SMALL else 600.0
@ -40,11 +37,6 @@ class ProfileBrowserWindow(bui.MainWindow):
else 385.0 if uiscale is bui.UIScale.MEDIUM else 410.0 else 385.0 if uiscale is bui.UIScale.MEDIUM else 410.0
) )
# If we're being called up standalone, handle pause/resume ourself.
if not self._in_main_menu:
assert bui.app.classic is not None
bui.app.classic.pause()
# Need to handle out-transitions ourself for modal mode. # Need to handle out-transitions ourself for modal mode.
if origin_widget is not None: if origin_widget is not None:
self._transition_out = 'out_scale' self._transition_out = 'out_scale'
@ -64,7 +56,7 @@ class ProfileBrowserWindow(bui.MainWindow):
size=(self._width, self._height + top_extra), size=(self._width, self._height + top_extra),
toolbar_visibility=( toolbar_visibility=(
'menu_minimal' 'menu_minimal'
if uiscale is bui.UIScale.SMALL if (uiscale is bui.UIScale.SMALL or minimal_toolbar)
else 'menu_full' else 'menu_full'
), ),
scale=( scale=(
@ -83,7 +75,7 @@ class ProfileBrowserWindow(bui.MainWindow):
if bui.app.ui_v1.uiscale is bui.UIScale.SMALL: if bui.app.ui_v1.uiscale is bui.UIScale.SMALL:
self._back_button = bui.get_special_widget('back_button') self._back_button = bui.get_special_widget('back_button')
bui.containerwidget( bui.containerwidget(
edit=self._root_widget, on_cancel_call=self._back edit=self._root_widget, on_cancel_call=self.main_window_back
) )
else: else:
self._back_button = btn = bui.buttonwidget( self._back_button = btn = bui.buttonwidget(
@ -92,18 +84,17 @@ class ProfileBrowserWindow(bui.MainWindow):
size=(120, 60), size=(120, 60),
scale=0.8, scale=0.8,
label=back_label, label=back_label,
button_type='back' if self._in_main_menu else None, button_type='back',
autoselect=True, autoselect=True,
on_activate_call=self._back, on_activate_call=self.main_window_back,
) )
bui.containerwidget(edit=self._root_widget, cancel_button=btn) bui.containerwidget(edit=self._root_widget, cancel_button=btn)
if self._in_main_menu: bui.buttonwidget(
bui.buttonwidget( edit=btn,
edit=btn, button_type='backSmall',
button_type='backSmall', size=(60, 60),
size=(60, 60), label=bui.charstr(bui.SpecialChar.BACK),
label=bui.charstr(bui.SpecialChar.BACK), )
)
bui.textwidget( bui.textwidget(
parent=self._root_widget, parent=self._root_widget,
@ -212,9 +203,14 @@ class ProfileBrowserWindow(bui.MainWindow):
def get_main_window_state(self) -> bui.MainWindowState: def get_main_window_state(self) -> bui.MainWindowState:
# Support recreating our window for back/refresh purposes. # Support recreating our window for back/refresh purposes.
cls = type(self) cls = type(self)
minimal_toolbar = self._minimal_toolbar
return bui.BasicMainWindowState( return bui.BasicMainWindowState(
create_call=lambda transition, origin_widget: cls( create_call=lambda transition, origin_widget: cls(
transition=transition, origin_widget=origin_widget transition=transition,
origin_widget=origin_widget,
minimal_toolbar=minimal_toolbar,
) )
) )
@ -227,10 +223,14 @@ class ProfileBrowserWindow(bui.MainWindow):
from bauiv1lib.profile.edit import EditProfileWindow from bauiv1lib.profile.edit import EditProfileWindow
from bauiv1lib.purchase import PurchaseWindow from bauiv1lib.purchase import PurchaseWindow
# no-op if our underlying widget is dead or on its way out. # No-op if we're not the in-control main window.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return 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
plus = bui.app.plus plus = bui.app.plus
assert plus is not None assert plus is not None
@ -266,14 +266,14 @@ class ProfileBrowserWindow(bui.MainWindow):
bui.getsound('error').play() bui.getsound('error').play()
return return
self._save_state() self.main_window_replace(EditProfileWindow(existing_profile=None))
bui.containerwidget(edit=self._root_widget, transition='out_left')
bui.app.ui_v1.set_main_window( # self._save_state()
EditProfileWindow( # bui.containerwidget(edit=self._root_widget, transition='out_left')
existing_profile=None, in_main_menu=self._in_main_menu # bui.app.ui_v1.set_main_window(
), # EditProfileWindow(existing_profile=None),
from_window=self if self._in_main_menu else False, # from_window=self if self._in_main_menu else False,
) # )
def _delete_profile(self) -> None: def _delete_profile(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
@ -321,8 +321,8 @@ class ProfileBrowserWindow(bui.MainWindow):
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.profile.edit import EditProfileWindow from bauiv1lib.profile.edit import EditProfileWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
if self._selected_profile is None: if self._selected_profile is None:
@ -331,49 +331,13 @@ class ProfileBrowserWindow(bui.MainWindow):
bui.Lstr(resource='nothingIsSelectedErrorText'), color=(1, 0, 0) bui.Lstr(resource='nothingIsSelectedErrorText'), color=(1, 0, 0)
) )
return return
self._save_state()
bui.containerwidget(edit=self._root_widget, transition='out_left') self.main_window_replace(EditProfileWindow(self._selected_profile))
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
EditProfileWindow(
self._selected_profile, in_main_menu=self._in_main_menu
),
from_window=self if self._in_main_menu else False,
)
def _select(self, name: str, index: int) -> None: def _select(self, name: str, index: int) -> None:
del index # Unused. del index # Unused.
self._selected_profile = name self._selected_profile = name
def _back(self) -> None:
# pylint: disable=cyclic-import
if self._in_main_menu:
self.main_window_back()
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
assert bui.app.classic is not None
self._save_state()
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
)
# if self._in_main_menu:
# assert bui.app.classic is not None
# bui.app.ui_v1.set_main_window(
# AccountSettingsWindow(transition='in_left'),
# from_window=self,
# is_back=True,
# )
# # If we're being called up standalone, handle pause/resume ourself.
# else:
bui.app.classic.resume()
def _refresh(self) -> None: def _refresh(self) -> None:
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
# pylint: disable=too-many-statements # pylint: disable=too-many-statements

View File

@ -26,8 +26,6 @@ class SendInfoWindow(bui.MainWindow):
): ):
self._legacy_code_mode = legacy_code_mode self._legacy_code_mode = legacy_code_mode
# scale_origin: tuple[float, float] | None
# Need to wrangle our own transition-out in modal mode. # Need to wrangle our own transition-out in modal mode.
if origin_widget is not None: if origin_widget is not None:
self._transition_out = 'out_scale' self._transition_out = 'out_scale'
@ -173,7 +171,7 @@ class SendInfoWindow(bui.MainWindow):
self.main_window_back() self.main_window_back()
return return
# from bauiv1lib.settings.advanced import AdvancedSettingsWindow # Handle modal case:
# no-op if our underlying widget is dead or on its way out. # 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._root_widget or self._root_widget.transitioning_out:
@ -182,40 +180,33 @@ class SendInfoWindow(bui.MainWindow):
bui.containerwidget( bui.containerwidget(
edit=self._root_widget, transition=self._transition_out edit=self._root_widget, transition=self._transition_out
) )
# if not self._modal:
# assert bui.app.classic is not None
# bui.app.ui_v1.set_main_window(
# AdvancedSettingsWindow(transition='in_left'),
# from_window=self,
# is_back=True,
# )
def _activate_enter_button(self) -> None: def _activate_enter_button(self) -> None:
self._enter_button.activate() self._enter_button.activate()
def _do_enter(self) -> None: def _do_enter(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.advanced import AdvancedSettingsWindow # from bauiv1lib.settings.advanced import AdvancedSettingsWindow
plus = bui.app.plus plus = bui.app.plus
assert plus is not None assert plus 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:
return
bui.containerwidget(
edit=self._root_widget, transition=self._transition_out
)
if not self._modal:
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
AdvancedSettingsWindow(transition='in_left'), from_window=self
)
description: Any = bui.textwidget(query=self._text_field) description: Any = bui.textwidget(query=self._text_field)
assert isinstance(description, str) assert isinstance(description, str)
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:
# no-op if we're not in control.
if not self.main_window_has_control():
return
self.main_window_back()
# Used for things like unlocking shared playlists or linking # Used for things like unlocking shared playlists or linking
# accounts: talk directly to V1 server via transactions. # accounts: talk directly to V1 server via transactions.
if self._legacy_code_mode: if self._legacy_code_mode:

View File

@ -721,32 +721,20 @@ class AdvancedSettingsWindow(bui.MainWindow):
def _on_vr_test_press(self) -> None: def _on_vr_test_press(self) -> None:
from bauiv1lib.settings.vrtesting import VRTestingWindow from bauiv1lib.settings.vrtesting import VRTestingWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(VRTestingWindow(transition='in_right'))
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
VRTestingWindow(transition='in_right'), from_window=self
)
def _on_net_test_press(self) -> None: def _on_net_test_press(self) -> None:
plus = bui.app.plus
assert plus is not None
from bauiv1lib.settings.nettesting import NetTestingWindow from bauiv1lib.settings.nettesting import NetTestingWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(NetTestingWindow(transition='in_right'))
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
NetTestingWindow(transition='in_right'), from_window=self
)
def _on_friend_promo_code_press(self) -> None: def _on_friend_promo_code_press(self) -> None:
from bauiv1lib import appinvite from bauiv1lib import appinvite
@ -763,64 +751,46 @@ class AdvancedSettingsWindow(bui.MainWindow):
def _on_plugins_button_press(self) -> None: def _on_plugins_button_press(self) -> None:
from bauiv1lib.settings.plugins import PluginWindow from bauiv1lib.settings.plugins import PluginWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') PluginWindow(origin_widget=self._plugins_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
PluginWindow(origin_widget=self._plugins_button), from_window=self
) )
def _on_dev_tools_button_press(self) -> None: def _on_dev_tools_button_press(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.devtools import DevToolsWindow from bauiv1lib.settings.devtools import DevToolsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') DevToolsWindow(origin_widget=self._dev_tools_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
DevToolsWindow(origin_widget=self._dev_tools_button),
from_window=self,
) )
def _on_send_info_press(self) -> None: def _on_send_info_press(self) -> None:
from bauiv1lib.sendinfo import SendInfoWindow from bauiv1lib.sendinfo import SendInfoWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
plus = bui.app.plus self.main_window_replace(
assert plus is not None SendInfoWindow(origin_widget=self._send_info_button)
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(
SendInfoWindow(origin_widget=self._send_info_button),
from_window=self,
) )
def _on_benchmark_press(self) -> None: def _on_benchmark_press(self) -> None:
from bauiv1lib.benchmarks import BenchmarksAndStressTestsWindow from bauiv1lib.benchmarks import BenchmarksAndStressTestsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') BenchmarksAndStressTestsWindow(transition='in_right')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
BenchmarksAndStressTestsWindow(transition='in_right'),
from_window=self,
) )
def _save_state(self) -> None: def _save_state(self) -> None:
@ -975,21 +945,3 @@ class AdvancedSettingsWindow(bui.MainWindow):
self._complete_langs_list = None self._complete_langs_list = None
self._complete_langs_error = True self._complete_langs_error = True
bui.apptimer(0.001, bui.WeakCall(self._update_lang_status)) bui.apptimer(0.001, bui.WeakCall(self._update_lang_status))
# def _do_back(self) -> None:
# from bauiv1lib.settings.allsettings import AllSettingsWindow
# # 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(
# AllSettingsWindow(transition='in_left'),
# from_window=self,
# is_back=True,
# )

View File

@ -240,64 +240,48 @@ class AllSettingsWindow(bui.MainWindow):
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.controls import ControlsSettingsWindow from bauiv1lib.settings.controls import ControlsSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') ControlsSettingsWindow(origin_widget=self._controllers_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
ControlsSettingsWindow(origin_widget=self._controllers_button),
from_window=self,
) )
def _do_graphics(self) -> None: def _do_graphics(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.graphics import GraphicsSettingsWindow from bauiv1lib.settings.graphics import GraphicsSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') GraphicsSettingsWindow(origin_widget=self._graphics_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
GraphicsSettingsWindow(origin_widget=self._graphics_button),
from_window=self,
) )
def _do_audio(self) -> None: def _do_audio(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.audio import AudioSettingsWindow from bauiv1lib.settings.audio import AudioSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') AudioSettingsWindow(origin_widget=self._audio_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
AudioSettingsWindow(origin_widget=self._audio_button),
from_window=self,
) )
def _do_advanced(self) -> None: def _do_advanced(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.advanced import AdvancedSettingsWindow from bauiv1lib.settings.advanced import AdvancedSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') AdvancedSettingsWindow(origin_widget=self._advanced_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
AdvancedSettingsWindow(origin_widget=self._advanced_button),
from_window=self,
) )
def _save_state(self) -> None: def _save_state(self) -> None:

View File

@ -65,9 +65,7 @@ class AudioSettingsWindow(bui.MainWindow):
(0, -20) if uiscale is bui.UIScale.SMALL else (0, 0) (0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
), ),
toolbar_visibility=( toolbar_visibility=(
'menu_minimal' None if uiscale is bui.UIScale.SMALL else 'menu_full'
if uiscale is bui.UIScale.SMALL
else 'menu_full'
), ),
), ),
transition=transition, transition=transition,
@ -241,14 +239,14 @@ class AudioSettingsWindow(bui.MainWindow):
def _do_soundtracks(self) -> None: def _do_soundtracks(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.soundtrack import browser as stb from bauiv1lib.soundtrack.browser import SoundtrackBrowserWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
# We require disk access for soundtracks; # We require disk access for soundtracks; request it if we don't
# if we don't have it, request it. # have it.
if not bui.have_permission(bui.Permission.STORAGE): if not bui.have_permission(bui.Permission.STORAGE):
bui.getsound('ding').play() bui.getsound('ding').play()
bui.screenmessage( bui.screenmessage(
@ -260,12 +258,8 @@ class AudioSettingsWindow(bui.MainWindow):
) )
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') SoundtrackBrowserWindow(origin_widget=self._soundtrack_button)
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
stb.SoundtrackBrowserWindow(origin_widget=self._soundtrack_button),
from_window=self,
) )
def _save_state(self) -> None: def _save_state(self) -> None:

View File

@ -6,7 +6,6 @@ from __future__ import annotations
from typing import override from typing import override
from bauiv1lib.popup import PopupMenu
import bascenev1 as bs import bascenev1 as bs
import bauiv1 as bui import bauiv1 as bui
@ -88,19 +87,6 @@ class ControlsSettingsWindow(bui.MainWindow):
if platform == 'windows' and not app.env.vr: if platform == 'windows' and not app.env.vr:
show_xinput_toggle = True show_xinput_toggle = True
# On mac builds, show an option to switch between generic and
# made-for-iOS/Mac systems
# (we can run into problems where devices register as one of each
# type otherwise)..
# UPDATE: We always use the apple system these days (which should
# support older controllers). So no need for a switch.
show_mac_controller_subsystem = False
# if platform == 'mac' and bui.is_xcode_build():
# show_mac_controller_subsystem = True
if show_mac_controller_subsystem:
height += spacing * 1.5
if show_xinput_toggle: if show_xinput_toggle:
height += spacing height += spacing
@ -339,48 +325,6 @@ class ControlsSettingsWindow(bui.MainWindow):
) )
v -= spacing v -= spacing
if show_mac_controller_subsystem:
PopupMenu(
parent=self._root_widget,
position=(260, v - 10),
width=160,
button_size=(150, 50),
scale=1.5,
choices=['Classic', 'MFi', 'Both'],
choices_display=[
bui.Lstr(resource='macControllerSubsystemClassicText'),
bui.Lstr(resource='macControllerSubsystemMFiText'),
bui.Lstr(resource='macControllerSubsystemBothText'),
],
current_choice=bui.app.config.resolve(
'Mac Controller Subsystem'
),
on_value_change_call=self._set_mac_controller_subsystem,
)
bui.textwidget(
parent=self._root_widget,
position=(245, v + 13),
size=(0, 0),
text=bui.Lstr(resource='macControllerSubsystemTitleText'),
scale=1.0,
h_align='right',
v_align='center',
color=bui.app.ui_v1.infotextcolor,
maxwidth=180,
)
bui.textwidget(
parent=self._root_widget,
position=(width * 0.5, v - 20),
size=(0, 0),
text=bui.Lstr(resource='macControllerSubsystemDescriptionText'),
scale=0.5,
h_align='center',
v_align='center',
color=bui.app.ui_v1.infotextcolor,
maxwidth=width * 0.8,
)
v -= spacing * 1.5
self._restore_state() self._restore_state()
@override @override
@ -406,76 +350,55 @@ class ControlsSettingsWindow(bui.MainWindow):
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.keyboard import ConfigKeyboardWindow from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') ConfigKeyboardWindow(bs.getinputdevice('Keyboard', '#1'))
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
ConfigKeyboardWindow(bs.getinputdevice('Keyboard', '#1')),
from_window=self,
) )
def _config_keyboard2(self) -> None: def _config_keyboard2(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.keyboard import ConfigKeyboardWindow from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(
bui.containerwidget(edit=self._root_widget, transition='out_left') ConfigKeyboardWindow(bs.getinputdevice('Keyboard', '#2'))
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
ConfigKeyboardWindow(bs.getinputdevice('Keyboard', '#2')),
from_window=self,
) )
def _do_mobile_devices(self) -> None: def _do_mobile_devices(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.remoteapp import RemoteAppSettingsWindow from bauiv1lib.settings.remoteapp import RemoteAppSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(RemoteAppSettingsWindow())
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
RemoteAppSettingsWindow(), from_window=self
)
def _do_gamepads(self) -> None: def _do_gamepads(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.gamepadselect import GamepadSelectWindow from bauiv1lib.settings.gamepadselect import GamepadSelectWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(GamepadSelectWindow())
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(GamepadSelectWindow(), from_window=self)
def _do_touchscreen(self) -> None: def _do_touchscreen(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.touchscreen import TouchscreenSettingsWindow from bauiv1lib.settings.touchscreen import TouchscreenSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we're not in control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(TouchscreenSettingsWindow())
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
TouchscreenSettingsWindow(), from_window=self
)
def _save_state(self) -> None: def _save_state(self) -> None:
sel = self._root_widget.get_selected_child() sel = self._root_widget.get_selected_child()
@ -516,22 +439,3 @@ class ControlsSettingsWindow(bui.MainWindow):
else self._back_button else self._back_button
) )
bui.containerwidget(edit=self._root_widget, selected_child=sel) bui.containerwidget(edit=self._root_widget, selected_child=sel)
# def _back(self) -> None:
# # pylint: disable=cyclic-import
# from bauiv1lib.settings.allsettings import AllSettingsWindow
# # 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(
# AllSettingsWindow(transition='in_left'),
# from_window=self,
# is_back=True,
# )

View File

@ -78,9 +78,7 @@ class GraphicsSettingsWindow(bui.MainWindow):
(0, -10) if uiscale is bui.UIScale.SMALL else (0, 0) (0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
), ),
toolbar_visibility=( toolbar_visibility=(
'menu_minimal' None if uiscale is bui.UIScale.SMALL else 'menu_full'
if uiscale is bui.UIScale.SMALL
else 'menu_full'
), ),
), ),
transition=transition, transition=transition,
@ -90,7 +88,6 @@ class GraphicsSettingsWindow(bui.MainWindow):
back_button = bui.buttonwidget( back_button = bui.buttonwidget(
parent=self._root_widget, parent=self._root_widget,
position=(35, height - 50), position=(35, height - 50),
# size=(120, 60),
size=(60, 60), size=(60, 60),
scale=0.8, scale=0.8,
text_scale=1.2, text_scale=1.2,

View File

@ -235,16 +235,11 @@ class PluginWindow(bui.MainWindow):
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bauiv1lib.settings.pluginsettings import PluginSettingsWindow from bauiv1lib.settings.pluginsettings import PluginSettingsWindow
# no-op if our underlying widget is dead or on its way out. # no-op if we don't have control.
if not self._root_widget or self._root_widget.transitioning_out: if not self.main_window_has_control():
return return
self._save_state() self.main_window_replace(PluginSettingsWindow(transition='in_right'))
bui.containerwidget(edit=self._root_widget, transition='out_left')
assert bui.app.classic is not None
bui.app.ui_v1.set_main_window(
PluginSettingsWindow(transition='in_right'), from_window=self
)
def _show_category_options(self) -> None: def _show_category_options(self) -> None:
uiscale = bui.app.ui_v1.uiscale uiscale = bui.app.ui_v1.uiscale

View File

@ -41,11 +41,11 @@ class StoreBrowserWindow(bui.MainWindow):
def __init__( def __init__(
self, self,
transition: str | None = 'in_right', transition: str | None = 'in_right',
origin_widget: bui.Widget | None = None,
# modal: bool = False, # modal: bool = False,
show_tab: StoreBrowserWindow.TabID | None = None, show_tab: StoreBrowserWindow.TabID | None = None,
# on_close_call: Callable[[], Any] | None = None, # on_close_call: Callable[[], Any] | None = None,
# back_location: str | None = None, # back_location: str | None = None,
origin_widget: bui.Widget | None = None,
minimal_toolbars: bool = False, minimal_toolbars: bool = False,
): ):
# pylint: disable=too-many-statements # pylint: disable=too-many-statements

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21985; const int kEngineBuildNumber = 21986;
const char* kEngineVersion = "1.7.37"; const char* kEngineVersion = "1.7.37";
const int kEngineApiVersion = 9; const int kEngineApiVersion = 9;

View File

@ -16,13 +16,16 @@ namespace ballistica::ui_v1 {
// Color we mult toolbars by in medium and large ui modes (in small mode we // Color we mult toolbars by in medium and large ui modes (in small mode we
// keep them more the normal window color since everything overlaps). // keep them more the normal window color since everything overlaps).
#define TOOLBAR_COLOR_R 0.75f #define TOOLBAR_COLOR_R 1.0f
#define TOOLBAR_COLOR_G 0.85f #define TOOLBAR_COLOR_G 1.0f
#define TOOLBAR_COLOR_B 0.85f #define TOOLBAR_COLOR_B 1.0f
// #define TOOLBAR_COLOR_R 0.75f
// #define TOOLBAR_COLOR_G 0.85f
// #define TOOLBAR_COLOR_B 0.85f
#define TOOLBAR_BACK_COLOR_R 0.8f #define TOOLBAR_BACK_COLOR_R 1.0f
#define TOOLBAR_BACK_COLOR_G 0.8f #define TOOLBAR_BACK_COLOR_G 1.0f
#define TOOLBAR_BACK_COLOR_B 0.8f #define TOOLBAR_BACK_COLOR_B 1.0f
// Opacity in med/large. // Opacity in med/large.
#define TOOLBAR_OPACITY 1.0f #define TOOLBAR_OPACITY 1.0f
@ -469,9 +472,9 @@ void RootWidget::AddMeter_(MeterType type, float h_align, float r, float g,
bd.color_g = 0.35f; bd.color_g = 0.35f;
bd.color_b = 0.55f; bd.color_b = 0.55f;
if (g_base->ui->scale() != UIScale::kSmall) { if (g_base->ui->scale() != UIScale::kSmall) {
bd.color_r *= TOOLBAR_COLOR_R; // bd.color_r *= TOOLBAR_COLOR_R;
bd.color_g *= TOOLBAR_COLOR_G; // bd.color_g *= TOOLBAR_COLOR_G;
bd.color_b *= TOOLBAR_COLOR_B; // bd.color_b *= TOOLBAR_COLOR_B;
} }
bd.depth_min = 0.3f; bd.depth_min = 0.3f;
switch (type) { switch (type) {
@ -662,9 +665,9 @@ void RootWidget::Setup() {
bd.color_b = 0.73f; bd.color_b = 0.73f;
bd.call = UIV1Python::ObjID::kRootUIAccountButtonPressCall; bd.call = UIV1Python::ObjID::kRootUIAccountButtonPressCall;
if (g_base->ui->scale() != UIScale::kSmall) { if (g_base->ui->scale() != UIScale::kSmall) {
bd.color_r *= TOOLBAR_COLOR_R; // bd.color_r *= TOOLBAR_COLOR_R;
bd.color_g *= TOOLBAR_COLOR_G; // bd.color_g *= TOOLBAR_COLOR_G;
bd.color_b *= TOOLBAR_COLOR_B; // bd.color_b *= TOOLBAR_COLOR_B;
} }
bd.pre_buffer = 10.0f; bd.pre_buffer = 10.0f;
bd.visibility_mask = bd.visibility_mask =
@ -1056,10 +1059,11 @@ void RootWidget::Setup() {
b.color_g = backing_cover_g; b.color_g = backing_cover_g;
b.color_b = backing_cover_b; b.color_b = backing_cover_b;
b.opacity = 1.0f; b.opacity = 1.0f;
b.call = UIV1Python::ObjID::kRootUIChestSlot3PressCall; b.call = UIV1Python::ObjID::kRootUIChestSlot2PressCall;
b.x = -0.5f * spacing; b.x = -0.5f * spacing;
AddButton_(b); AddButton_(b);
b.x = 0.5f * spacing; b.x = 0.5f * spacing;
b.call = UIV1Python::ObjID::kRootUIChestSlot3PressCall;
AddButton_(b); AddButton_(b);
b.x = 1.5f * spacing; b.x = 1.5f * spacing;
b.call = UIV1Python::ObjID::kRootUIChestSlot4PressCall; b.call = UIV1Python::ObjID::kRootUIChestSlot4PressCall;