mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-27 17:33:13 +08:00
hopefully finally fixed multi-ui bug for real this time
This commit is contained in:
parent
d5339e3193
commit
0e15df6f59
58
.efrocachemap
generated
58
.efrocachemap
generated
@ -4060,26 +4060,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": "9fe23e06319e4e256b9fa88814a14afa",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "4306acae21ce88235f9d1589086866e7",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "75e4f7d3a3df67dedd079ec3f4441094",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "bd5eda13f239b81886ac80596d6ade73",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "0805235a92dd91f96d43ea54575eecac",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "07589a61b11cbc5fca0bbc8b7fc1c955",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "f28629761060c8152168b6792b71adae",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "1cfd1a33474cdb31834994f626385ed0",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d50879a92d9d344c376f6f196d78d1be",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "78cd0edf2698f197f2acd80ca364fae7",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d656f47118ebc3af57c40423cb258bc8",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "75df540b27779342a7c696e1bdbe593f",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "76f0dfacaa9ea67e45e8ccf3bb3bc1c6",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "2acc754bed825a9265e0621dc09899e0",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "62c2b6190de8784ea8750ea50e6a2304",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "e57358fd9a948a8ce82a54cdd5c766fc",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "d36e3303e13049eae5e7ec19861d300e",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "46971a2ca1e3021e52ea5d0f4938d2ff",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "19ebd36613cf62c4bd50e70b93371368",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "49ef5905b6e9e1a9caaed3d1c1da4ea5",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "c2b80379179c8731be37581e52259377",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "0a2257e46a20ae6453d888515a00f1a8",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "a8bf3602e161931f96c41989d9d4e630",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "15e5d036605366840182cf3f86d247ae",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "4212f5014bcf30f5ceb6e9ed00c1b443",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "a9ee1b8f07dc7466b4daf90a34991f3b",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "cbc9bf3f8ddce331912b6dbd8f1c6415",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "6b4458aa454391fa0070099ef4cac711",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "fae27ee9108877bd75aaa222f02f239d",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "37f2b4219ffe85aa1d28ab7df7fd4c44",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "3f8de90abf2069a0881f8d91f1ec78b2",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "62a6ee7583ef9d83f9bb1601fce6ddaa",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "f495a8547ca8b824f80006603537d1cf",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "672c351fca7843d85a2be7aba13faf1f",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "50f6d105ad4c2bb2df4f3d335b6d2cfa",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "44e1d633accc2410ca6d825e4c464f45",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "5cce0ce595304313ac28c02e235f19d7",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "9433fc9da2f4b7255f2c7fa95868604a",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "18eb1871a6db9bbe17f5e9678d3d492a",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "cf51dafe0553d06a44349d0911c21d71",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "c22901e06e88a55cce0b4e08bbf41a4c",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "a27963487e346338e4c216bd4fbb9e2a",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "c22901e06e88a55cce0b4e08bbf41a4c",
|
||||
@ -4096,14 +4096,14 @@
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "852fe46c736082611a831a618923c241",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "36fbda7829ed5c2862c34feb09b03402",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "852fe46c736082611a831a618923c241",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "38b4b5b85a9bafdb76222d0f0c962b06",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "9a8af3d217bcb0bacfaed4c30dd5f42e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "6d10ca306f60d66efb4942636e4955d6",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "1c65d36e4420ed79380dc8c041c94a8b",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9b1b72f3d41c89a6b06288be63e8f40a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "e0f2eb8ea024bc88e999b9dc16317fd4",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "42be1225757328f432d91de950444ba0",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "05bc2832cc0c9fba308668fc1a6d3b0f",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "8ec03141da397548f8a06259222c14e3",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "9f20a365cc0ec1831e0e301a34198b0e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "37980dc34b9ad281cdab738f7053af26",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "148e0f3a1ee77607d0b93a636b253295",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "e20a2aa49741757075634f422dc5ac7a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "fa7018f7c2ee8c952bff7879b92709cb",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "cd38a41872e74b43de005375330e3cd0",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5bc4faf70f09f56e2ced27cafe2ad3e6",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f",
|
||||
@ -4114,5 +4114,5 @@
|
||||
"src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5",
|
||||
"src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "d80f970053099b3044204bfe29ddefce",
|
||||
"src/ballistica/template_fs/mgen/pyembed/binding_template_fs.inc": "44a45492db057bf7f7158c3b0fa11f0f",
|
||||
"src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "8f4c2070174bdc2fbf735180394d7b3a"
|
||||
"src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "f5f054050d2b2fcd3763a4833fb32269"
|
||||
}
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,4 +1,4 @@
|
||||
### 1.7.30 (build 21636, api 8, 2023-11-30)
|
||||
### 1.7.30 (build 21639, api 8, 2023-11-30)
|
||||
- Continued work on the big 1.7.28 update.
|
||||
- Got the Android version back up and running. There's been lots of cleanup and
|
||||
simplification on the Android layer, cleaning out years of cruft. This should
|
||||
@ -21,9 +21,16 @@
|
||||
builds when tv-border was on (Thanks for the heads-up Loup(Dliwk's fan)!).
|
||||
- (build 21631) Fixes an issue where '^^^^^^^^^^^^^' lines in stack traces could
|
||||
get chopped into tiny bits each on their own line in the dev console.
|
||||
- Fixed a longstanding issue where multiple key presses simultaneously could
|
||||
cause multiple windows to pop up where only one is expected. Please holler if
|
||||
you still see this problem happening anywhere.
|
||||
- Hopefully finally fixed a longstanding issue where obscure cases such as
|
||||
multiple key presses simultaneously could cause multiple main menu windows to
|
||||
pop up. Please holler if you still see this problem happening anywhere. Also
|
||||
added a few related safety checks and warnings to help ensure UI code is free
|
||||
from such problems going forward. To make sure your custom UIs are behaving
|
||||
well in this system, do the following two things: 1) any time you call
|
||||
`set_main_menu_window()`, pass your existing main menu window root widget as
|
||||
`from_window`. 2) In any call that can lead to you switching the main menu
|
||||
window, check if your root widget is dead or transitioning out first and abort
|
||||
if it is. See any window in `ui_v1_lib` for examples.
|
||||
|
||||
### 1.7.29 (build 21619, api 8, 2023-11-21)
|
||||
|
||||
|
||||
@ -41,5 +41,6 @@ class AppDelegate:
|
||||
sessiontype,
|
||||
settings,
|
||||
completion_call=completion_call,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check since we don't know.
|
||||
)
|
||||
|
||||
@ -800,5 +800,6 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
bauiv1.getsound('swish').play()
|
||||
|
||||
babase.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow().get_root_widget()
|
||||
MainMenuWindow().get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21636
|
||||
TARGET_BALLISTICA_BUILD = 21639
|
||||
TARGET_BALLISTICA_VERSION = '1.7.30'
|
||||
|
||||
|
||||
|
||||
@ -317,7 +317,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
from bauiv1lib.kiosk import KioskWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
KioskWindow().get_root_widget()
|
||||
KioskWindow().get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
# ..or in normal cases go back to the main menu
|
||||
else:
|
||||
@ -326,14 +327,16 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
from bauiv1lib.gather import GatherWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(transition=None).get_root_widget()
|
||||
GatherWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Watch':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.watch import WatchWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
WatchWindow(transition=None).get_root_widget()
|
||||
WatchWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Team Game Select':
|
||||
# pylint: disable=cyclic-import
|
||||
@ -344,7 +347,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
PlaylistBrowserWindow(
|
||||
sessiontype=bs.DualTeamSession, transition=None
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Free-for-All Game Select':
|
||||
# pylint: disable=cyclic-import
|
||||
@ -356,28 +360,34 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
PlaylistBrowserWindow(
|
||||
sessiontype=bs.FreeForAllSession,
|
||||
transition=None,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Coop Select':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(transition=None).get_root_widget()
|
||||
CoopBrowserWindow(
|
||||
transition=None
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Benchmarks & Stress Tests':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.debug import DebugWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
DebugWindow(transition=None).get_root_widget()
|
||||
DebugWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
else:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition=None).get_root_widget()
|
||||
MainMenuWindow(transition=None).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
|
||||
# attempt to show any pending offers immediately.
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _bauiv1
|
||||
@ -87,3 +88,19 @@ def show_url_window(address: str) -> None:
|
||||
return
|
||||
|
||||
app.classic.show_url_window(address)
|
||||
|
||||
|
||||
def double_transition_out_warning() -> None:
|
||||
"""Called if a widget is set to transition out twice."""
|
||||
caller_frame = inspect.stack()[1]
|
||||
caller_filename = caller_frame.filename
|
||||
caller_line_number = caller_frame.lineno
|
||||
logging.warning(
|
||||
'ContainerWidget was set to transition out twice;'
|
||||
' this often implies buggy code (%s line %s).\n'
|
||||
' Generally you should check the value of'
|
||||
' _root_widget.transitioning_out and only kick off transitions'
|
||||
' when that is False.',
|
||||
caller_filename,
|
||||
caller_line_number,
|
||||
)
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
@ -116,21 +117,69 @@ class UIV1Subsystem(babase.AppSubsystem):
|
||||
# FIXME: Can probably kill this if we do immediate UI death checks.
|
||||
self.upkeeptimer = babase.AppTimer(2.6543, ui_upkeep, repeat=True)
|
||||
|
||||
def set_main_menu_window(self, window: bauiv1.Widget) -> None:
|
||||
"""Set the current 'main' window, replacing any existing."""
|
||||
def set_main_menu_window(
|
||||
self,
|
||||
window: bauiv1.Widget,
|
||||
from_window: bauiv1.Widget | None | bool = True,
|
||||
) -> None:
|
||||
"""Set the current 'main' window, replacing any existing.
|
||||
|
||||
If 'from_window' is passed as a bauiv1.Widget or None, a warning
|
||||
will be issued if it that value does not match the current main
|
||||
window. This can help clean up flawed code that can lead to bad
|
||||
UI states. A value of False will disable the check.
|
||||
"""
|
||||
|
||||
existing = self._main_menu_window
|
||||
from inspect import currentframe, getframeinfo
|
||||
|
||||
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_menu_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_menu_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')
|
||||
|
||||
# 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 = currentframe()
|
||||
frame = inspect.currentframe()
|
||||
if frame is not None:
|
||||
frame = frame.f_back
|
||||
if frame is not None:
|
||||
frameinfo = getframeinfo(frame)
|
||||
frameinfo = inspect.getframeinfo(frame)
|
||||
frameline = f'{frameinfo.filename} {frameinfo.lineno}'
|
||||
except Exception:
|
||||
logging.exception('Error calcing line for set_main_menu_window')
|
||||
@ -167,6 +216,7 @@ class UIV1Subsystem(babase.AppSubsystem):
|
||||
)
|
||||
else:
|
||||
self._main_menu_window.delete()
|
||||
self._main_menu_window = None
|
||||
|
||||
def add_main_menu_close_callback(self, call: Callable[[], Any]) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
@ -1507,9 +1507,18 @@ class AccountSettingsWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# 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='out_left')
|
||||
ProfileBrowserWindow(origin_widget=self._player_profiles_button)
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ProfileBrowserWindow(
|
||||
origin_widget=self._player_profiles_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _cancel_sign_in_press(self) -> None:
|
||||
# If we're waiting on an adapter to give us credentials, abort.
|
||||
@ -1670,6 +1679,10 @@ class AccountSettingsWindow(bui.Window):
|
||||
# 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:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
@ -1678,7 +1691,8 @@ class AccountSettingsWindow(bui.Window):
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -1019,6 +1019,10 @@ class CoopBrowserWindow(bui.Window):
|
||||
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
|
||||
|
||||
@ -1032,7 +1036,8 @@ class CoopBrowserWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
LeagueRankWindow(
|
||||
origin_widget=self._league_rank_button.get_button()
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _switch_to_score(
|
||||
@ -1043,6 +1048,10 @@ class CoopBrowserWindow(bui.Window):
|
||||
# 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
|
||||
|
||||
@ -1058,7 +1067,8 @@ class CoopBrowserWindow(bui.Window):
|
||||
origin_widget=self._store_button.get_button(),
|
||||
show_tab=show_tab,
|
||||
back_location='CoopBrowserWindow',
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def is_tourney_data_up_to_date(self) -> bool:
|
||||
@ -1218,6 +1228,10 @@ class CoopBrowserWindow(bui.Window):
|
||||
# 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(
|
||||
@ -1225,7 +1239,8 @@ class CoopBrowserWindow(bui.Window):
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(transition='in_left').get_root_widget()
|
||||
PlayWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -359,10 +359,15 @@ class CreditsListWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
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:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -379,8 +379,13 @@ class DebugWindow(bui.Window):
|
||||
# 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
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget()
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -270,12 +270,17 @@ class GatherWindow(bui.Window):
|
||||
"""Called by the private-hosting tab to select a playlist."""
|
||||
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
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.selecting_private_party_playlist = True
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(origin_widget=origin_widget).get_root_widget()
|
||||
PlayWindow(origin_widget=origin_widget).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _set_tab(self, tab_id: TabID) -> None:
|
||||
@ -383,11 +388,16 @@ class GatherWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
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:
|
||||
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_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -732,8 +732,13 @@ class GetCurrencyWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.store import browser
|
||||
|
||||
# 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._transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
@ -745,7 +750,9 @@ class GetCurrencyWindow(bui.Window):
|
||||
).get_root_widget()
|
||||
if not self._from_modal_store:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(window)
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
window, from_window=self._root_widget
|
||||
)
|
||||
self._transitioning_out = True
|
||||
|
||||
|
||||
|
||||
@ -645,11 +645,16 @@ class HelpWindow(bui.Window):
|
||||
# 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:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if self._main_menu:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -501,9 +501,15 @@ class KioskWindow(bui.Window):
|
||||
def _do_full_menu(self) -> None:
|
||||
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:
|
||||
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_menu_window(MainMenuWindow().get_root_widget())
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow().get_root_widget(), from_window=self._root_widget
|
||||
)
|
||||
|
||||
@ -1142,6 +1142,10 @@ class LeagueRankWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
# 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
|
||||
@ -1149,5 +1153,6 @@ class LeagueRankWindow(bui.Window):
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(transition='in_left').get_root_widget()
|
||||
CoopBrowserWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -1038,6 +1038,10 @@ class MainMenuWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.confirm import QuitWindow
|
||||
|
||||
# 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
|
||||
|
||||
# Note: Normally we should go through bui.quit(confirm=True) but
|
||||
# invoking the window directly lets us scale it up from the
|
||||
# button.
|
||||
@ -1047,24 +1051,34 @@ class MainMenuWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.kiosk import KioskWindow
|
||||
|
||||
# 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='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
KioskWindow(transition='in_left').get_root_widget()
|
||||
KioskWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _show_account_window(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.account.settings import AccountSettingsWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AccountSettingsWindow(
|
||||
origin_widget=self._account_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _on_store_pressed(self) -> None:
|
||||
@ -1072,6 +1086,10 @@ class MainMenuWindow(bui.Window):
|
||||
from bauiv1lib.store.browser import StoreBrowserWindow
|
||||
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
|
||||
|
||||
@ -1084,7 +1102,8 @@ class MainMenuWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
StoreBrowserWindow(
|
||||
origin_widget=self._store_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _is_benchmark(self) -> bool:
|
||||
@ -1149,8 +1168,11 @@ class MainMenuWindow(bui.Window):
|
||||
|
||||
def _end_game(self) -> None:
|
||||
assert bui.app.classic is not None
|
||||
if not self._root_widget:
|
||||
|
||||
# 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_left')
|
||||
bui.app.classic.return_to_main_menu_session_gracefully(reset_ui=False)
|
||||
|
||||
@ -1166,39 +1188,54 @@ class MainMenuWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.creditslist import CreditsListWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
CreditsListWindow(
|
||||
origin_widget=self._credits_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _howtoplay(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.helpui import HelpWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
HelpWindow(
|
||||
main_menu=True, origin_widget=self._how_to_play_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _settings(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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AllSettingsWindow(
|
||||
origin_widget=self._settings_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _resume_and_call(self, call: Callable[[], Any]) -> None:
|
||||
@ -1281,35 +1318,50 @@ class MainMenuWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.gather import GatherWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(origin_widget=self._gather_button).get_root_widget()
|
||||
GatherWindow(origin_widget=self._gather_button).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _watch_press(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.watch import WatchWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
WatchWindow(origin_widget=self._watch_button).get_root_widget()
|
||||
WatchWindow(origin_widget=self._watch_button).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _play_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:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.selecting_private_party_playlist = False
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(origin_widget=self._start_button).get_root_widget()
|
||||
PlayWindow(origin_widget=self._start_button).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _resume(self) -> None:
|
||||
|
||||
@ -521,13 +521,19 @@ class PlayWindow(bui.Window):
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
# 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._is_main_menu:
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
self._save_state()
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
@ -538,7 +544,8 @@ class PlayWindow(bui.Window):
|
||||
self._save_state()
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(transition='in_left').get_root_widget()
|
||||
GatherWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
@ -549,6 +556,10 @@ class PlayWindow(bui.Window):
|
||||
from bauiv1lib.account import show_sign_in_prompt
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
# 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
|
||||
|
||||
@ -559,26 +570,38 @@ class PlayWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(origin_widget=self._coop_button).get_root_widget()
|
||||
CoopBrowserWindow(
|
||||
origin_widget=self._coop_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _team_tourney(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.browser import PlaylistBrowserWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistBrowserWindow(
|
||||
origin_widget=self._teams_button, sessiontype=bs.DualTeamSession
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _free_for_all(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.browser import PlaylistBrowserWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
@ -586,7 +609,8 @@ class PlayWindow(bui.Window):
|
||||
PlaylistBrowserWindow(
|
||||
origin_widget=self._free_for_all_button,
|
||||
sessiontype=bs.FreeForAllSession,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _draw_dude(
|
||||
|
||||
@ -684,6 +684,10 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
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:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
@ -691,13 +695,18 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
PlaylistCustomizeBrowserWindow(
|
||||
origin_widget=self._customize_button,
|
||||
sessiontype=self._sessiontype,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
# Store our selected playlist if that's changed.
|
||||
if self._selected_playlist is not None:
|
||||
prev_sel = bui.app.config.get(
|
||||
@ -716,7 +725,8 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(transition='in_left').get_root_widget()
|
||||
PlayWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -323,6 +323,10 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist import browser
|
||||
|
||||
# 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._selected_playlist_name is not None:
|
||||
cfg = bui.app.config
|
||||
cfg[
|
||||
@ -337,7 +341,8 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
browser.PlaylistBrowserWindow(
|
||||
transition='in_left', sessiontype=self._sessiontype
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _select(self, name: str, index: int) -> None:
|
||||
|
||||
@ -283,6 +283,10 @@ class PlaylistEditWindow(bui.Window):
|
||||
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:
|
||||
return
|
||||
|
||||
bui.getsound('powerdown01').play()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
@ -293,7 +297,8 @@ class PlaylistEditWindow(bui.Window):
|
||||
select_playlist=(
|
||||
self._editcontroller.get_existing_playlist_name()
|
||||
),
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _add(self) -> None:
|
||||
@ -315,6 +320,10 @@ class PlaylistEditWindow(bui.Window):
|
||||
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:
|
||||
return
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
@ -380,7 +389,8 @@ class PlaylistEditWindow(bui.Window):
|
||||
transition='in_left',
|
||||
sessiontype=self._editcontroller.get_session_type(),
|
||||
select_playlist=new_name,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_press_with_sound(self) -> None:
|
||||
|
||||
@ -92,7 +92,8 @@ class PlaylistEditController:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition=transition
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable this check.
|
||||
)
|
||||
|
||||
def get_config_name(self) -> str:
|
||||
@ -150,7 +151,8 @@ class PlaylistEditController:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_left')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistAddGameWindow(editcontroller=self).get_root_widget()
|
||||
PlaylistAddGameWindow(editcontroller=self).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
|
||||
def edit_game_pressed(self) -> None:
|
||||
@ -175,7 +177,8 @@ class PlaylistEditController:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
|
||||
def _show_edit_ui(
|
||||
@ -205,7 +208,8 @@ class PlaylistEditController:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
|
||||
# Otherwise we were adding; go back to the add type choice list.
|
||||
@ -214,7 +218,8 @@ class PlaylistEditController:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistAddGameWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
else:
|
||||
# Make sure type is in there.
|
||||
@ -236,5 +241,6 @@ class PlaylistEditController:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
|
||||
@ -514,6 +514,10 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.mapselect import PlaylistMapSelectWindow
|
||||
|
||||
# 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
|
||||
|
||||
# Replace ourself with the map-select UI.
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
@ -524,7 +528,8 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
copy.deepcopy(self._getconfig()),
|
||||
self._edit_info,
|
||||
self._completion_call,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _choice_inc(
|
||||
|
||||
@ -273,6 +273,10 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
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:
|
||||
return
|
||||
|
||||
self._config['settings']['map'] = map_name
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
@ -285,7 +289,8 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
default_selection='map',
|
||||
transition='in_left',
|
||||
edit_info=self._edit_info,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _select_with_delay(self, map_name: str) -> None:
|
||||
@ -296,6 +301,10 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
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_menu_window(
|
||||
@ -307,5 +316,6 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
default_selection='map',
|
||||
transition='in_left',
|
||||
edit_info=self._edit_info,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -140,7 +140,6 @@ class PlayOptionsWindow(PopupWindow):
|
||||
if show_shuffle_check_box:
|
||||
self._height += 40
|
||||
|
||||
# Creates our _root_widget.
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
scale = (
|
||||
1.69
|
||||
@ -149,6 +148,7 @@ class PlayOptionsWindow(PopupWindow):
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
else 0.85
|
||||
)
|
||||
# Creates our _root_widget.
|
||||
super().__init__(
|
||||
position=scale_origin, size=(self._width, self._height), scale=scale
|
||||
)
|
||||
@ -448,6 +448,10 @@ class PlayOptionsWindow(PopupWindow):
|
||||
self._transition_out()
|
||||
|
||||
def _on_ok_press(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
|
||||
|
||||
# Disallow if our playlist has disappeared.
|
||||
if not self._does_target_playlist_exist():
|
||||
return
|
||||
@ -479,7 +483,8 @@ class PlayOptionsWindow(PopupWindow):
|
||||
bui.getsound('gunCocking').play()
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(transition='in_right').get_root_widget()
|
||||
GatherWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self.root_widget,
|
||||
)
|
||||
self._transition_out(transition='out_left')
|
||||
if self._delegate is not None:
|
||||
|
||||
@ -212,6 +212,10 @@ class ProfileBrowserWindow(bui.Window):
|
||||
from bauiv1lib.profile.edit import EditProfileWindow
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
|
||||
# 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
|
||||
|
||||
@ -252,7 +256,8 @@ class ProfileBrowserWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
EditProfileWindow(
|
||||
existing_profile=None, in_main_menu=self._in_main_menu
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _delete_profile(self) -> None:
|
||||
@ -301,6 +306,10 @@ class ProfileBrowserWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.profile.edit import EditProfileWindow
|
||||
|
||||
# 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._selected_profile is None:
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
@ -313,7 +322,8 @@ class ProfileBrowserWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
EditProfileWindow(
|
||||
self._selected_profile, in_main_menu=self._in_main_menu
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _select(self, name: str, index: int) -> None:
|
||||
@ -324,6 +334,10 @@ class ProfileBrowserWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.account.settings import AccountSettingsWindow
|
||||
|
||||
# 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()
|
||||
@ -333,7 +347,8 @@ class ProfileBrowserWindow(bui.Window):
|
||||
if self._in_main_menu:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AccountSettingsWindow(transition='in_left').get_root_widget()
|
||||
AccountSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
# If we're being called up standalone, handle pause/resume ourself.
|
||||
|
||||
@ -18,12 +18,18 @@ class EditProfileWindow(bui.Window):
|
||||
# FIXME: WILL NEED TO CHANGE THIS FOR UILOCATION.
|
||||
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:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
EditProfileWindow(
|
||||
self.getname(), self._in_main_menu
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@ -653,6 +659,10 @@ class EditProfileWindow(bui.Window):
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# 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_menu_window(
|
||||
@ -660,7 +670,8 @@ class EditProfileWindow(bui.Window):
|
||||
'in_left',
|
||||
selected_profile=self._existing_profile,
|
||||
in_main_menu=self._in_main_menu,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _set_color(self, color: tuple[float, float, float]) -> None:
|
||||
@ -759,6 +770,10 @@ class EditProfileWindow(bui.Window):
|
||||
"""Save has been selected."""
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# 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 False
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
@ -808,6 +823,7 @@ class EditProfileWindow(bui.Window):
|
||||
'in_left',
|
||||
selected_profile=new_name,
|
||||
in_main_menu=self._in_main_menu,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
return True
|
||||
|
||||
@ -142,13 +142,18 @@ class PromoCodeWindow(bui.Window):
|
||||
# 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
|
||||
|
||||
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_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget()
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _activate_enter_button(self) -> None:
|
||||
@ -158,6 +163,10 @@ class PromoCodeWindow(bui.Window):
|
||||
# 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
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
@ -167,7 +176,8 @@ class PromoCodeWindow(bui.Window):
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget()
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
plus.add_v1_account_transaction(
|
||||
{
|
||||
|
||||
@ -682,11 +682,16 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
def _on_vr_test_press(self) -> None:
|
||||
from bauiv1lib.settings.vrtesting import VRTestingWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
VRTestingWindow(transition='in_right').get_root_widget()
|
||||
VRTestingWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _on_net_test_press(self) -> None:
|
||||
@ -694,6 +699,10 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
assert plus is not None
|
||||
from bauiv1lib.settings.nettesting import NetTestingWindow
|
||||
|
||||
# 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
|
||||
|
||||
# Net-testing requires a signed in v1 account.
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
bui.screenmessage(
|
||||
@ -706,7 +715,8 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
NetTestingWindow(transition='in_right').get_root_widget()
|
||||
NetTestingWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _on_friend_promo_code_press(self) -> None:
|
||||
@ -724,17 +734,26 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
def _on_plugins_button_press(self) -> None:
|
||||
from bauiv1lib.settings.plugins import PluginWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PluginWindow(origin_widget=self._plugins_button).get_root_widget()
|
||||
PluginWindow(origin_widget=self._plugins_button).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _on_promo_code_press(self) -> None:
|
||||
from bauiv1lib.promocode import PromoCodeWindow
|
||||
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
|
||||
|
||||
@ -742,23 +761,30 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
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 bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PromoCodeWindow(
|
||||
origin_widget=self._promo_code_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _on_benchmark_press(self) -> None:
|
||||
from bauiv1lib.debug import DebugWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
DebugWindow(transition='in_right').get_root_widget()
|
||||
DebugWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
@ -908,11 +934,16 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
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_menu_window(
|
||||
AllSettingsWindow(transition='in_left').get_root_widget()
|
||||
AllSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -235,65 +235,90 @@ class AllSettingsWindow(bui.Window):
|
||||
# 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:
|
||||
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_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_controllers(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
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:
|
||||
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_menu_window(
|
||||
ControlsSettingsWindow(
|
||||
origin_widget=self._controllers_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_graphics(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.graphics import GraphicsSettingsWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GraphicsSettingsWindow(
|
||||
origin_widget=self._graphics_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_audio(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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AudioSettingsWindow(
|
||||
origin_widget=self._audio_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_advanced(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
|
||||
|
||||
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_menu_window(
|
||||
AdvancedSettingsWindow(
|
||||
origin_widget=self._advanced_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -237,6 +237,10 @@ class AudioSettingsWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.soundtrack import browser as stb
|
||||
|
||||
# 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
|
||||
|
||||
# We require disk access for soundtracks;
|
||||
# if we don't have it, request it.
|
||||
if not bui.have_permission(bui.Permission.STORAGE):
|
||||
@ -256,13 +260,18 @@ class AudioSettingsWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
stb.SoundtrackBrowserWindow(
|
||||
origin_widget=self._soundtrack_button
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings import allsettings
|
||||
|
||||
# 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
|
||||
@ -271,7 +280,8 @@ class AudioSettingsWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
allsettings.AllSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -367,59 +367,84 @@ class ControlsSettingsWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ConfigKeyboardWindow(
|
||||
bs.getinputdevice('Keyboard', '#1')
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _config_keyboard2(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.keyboard import ConfigKeyboardWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ConfigKeyboardWindow(
|
||||
bs.getinputdevice('Keyboard', '#2')
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_mobile_devices(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.remoteapp import RemoteAppSettingsWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
RemoteAppSettingsWindow().get_root_widget()
|
||||
RemoteAppSettingsWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_gamepads(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.gamepadselect import GamepadSelectWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GamepadSelectWindow().get_root_widget()
|
||||
GamepadSelectWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_touchscreen(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.touchscreen import TouchscreenSettingsWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
TouchscreenSettingsWindow().get_root_widget()
|
||||
TouchscreenSettingsWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
@ -466,11 +491,16 @@ class ControlsSettingsWindow(bui.Window):
|
||||
# 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_menu_window(
|
||||
AllSettingsWindow(transition='in_left').get_root_widget()
|
||||
AllSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -795,19 +795,28 @@ class GamepadSettingsWindow(bui.Window):
|
||||
def _cancel(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:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if self._is_main_menu:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget()
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save(self) -> None:
|
||||
classic = bui.app.classic
|
||||
assert 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:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
@ -852,7 +861,8 @@ class GamepadSettingsWindow(bui.Window):
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget()
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -33,7 +33,8 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
assert isinstance(device, bs.InputDevice)
|
||||
if device.allows_configuring:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
gamepad.GamepadSettingsWindow(device).get_root_widget()
|
||||
gamepad.GamepadSettingsWindow(device).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
else:
|
||||
width = 700
|
||||
@ -51,7 +52,7 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
size=(width, height),
|
||||
transition='in_right',
|
||||
)
|
||||
bui.app.ui_v1.set_main_menu_window(dlg)
|
||||
bui.app.ui_v1.set_main_menu_window(dlg, from_window=None)
|
||||
|
||||
if device.allows_configuring_in_system_settings:
|
||||
msg = bui.Lstr(
|
||||
@ -81,12 +82,17 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
def _ok() -> None:
|
||||
from bauiv1lib.settings import controls
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not dlg or dlg.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=dlg, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=dlg,
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
@ -191,11 +197,16 @@ class GamepadSelectWindow(bui.Window):
|
||||
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
|
||||
|
||||
bs.release_gamepad_input()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -436,6 +436,10 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.settings import allsettings
|
||||
|
||||
# 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
|
||||
|
||||
# Applying max-fps takes a few moments. Apply if it hasn't been
|
||||
# yet.
|
||||
self._apply_max_fps()
|
||||
@ -447,7 +451,8 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
allsettings.AllSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _set_quality(self, quality: str) -> None:
|
||||
|
||||
@ -271,15 +271,24 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
def _cancel(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:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget()
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
bui.getsound('gunCocking').play()
|
||||
@ -314,7 +323,8 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
)
|
||||
bui.app.config.apply_and_commit()
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget()
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -135,8 +135,14 @@ class NetTestingWindow(bui.Window):
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
NetValTestingWindow().get_root_widget()
|
||||
NetValTestingWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
@ -144,9 +150,14 @@ class NetTestingWindow(bui.Window):
|
||||
# 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_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget()
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
|
||||
|
||||
@ -212,11 +212,16 @@ class PluginWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.pluginsettings import PluginSettingsWindow
|
||||
|
||||
# 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='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PluginSettingsWindow(transition='in_right').get_root_widget()
|
||||
PluginSettingsWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _show_category_options(self) -> None:
|
||||
@ -412,11 +417,16 @@ class PluginWindow(bui.Window):
|
||||
# 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
|
||||
|
||||
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_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget()
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -161,10 +161,15 @@ class PluginSettingsWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.plugins import PluginWindow
|
||||
|
||||
# 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
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PluginWindow(transition='in_left').get_root_widget()
|
||||
PluginWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -138,10 +138,15 @@ class RemoteAppSettingsWindow(bui.Window):
|
||||
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_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -217,6 +217,10 @@ class TestingWindow(bui.Window):
|
||||
# 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
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
backwin = (
|
||||
self._back_call()
|
||||
@ -224,4 +228,6 @@ class TestingWindow(bui.Window):
|
||||
else AdvancedSettingsWindow(transition='in_left')
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(backwin.get_root_widget())
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
backwin.get_root_widget(), from_window=self._root_widget
|
||||
)
|
||||
|
||||
@ -276,11 +276,16 @@ class TouchscreenSettingsWindow(bui.Window):
|
||||
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_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bs.set_touchscreen_editing(False)
|
||||
|
||||
@ -394,13 +394,18 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings import audio
|
||||
|
||||
# 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_menu_window(
|
||||
audio.AudioSettingsWindow(transition='in_left').get_root_widget()
|
||||
audio.AudioSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _edit_soundtrack_with_sound(self) -> None:
|
||||
@ -421,6 +426,10 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
from bauiv1lib.soundtrack.edit import SoundtrackEditWindow
|
||||
|
||||
# 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 (
|
||||
bui.app.classic is not None
|
||||
and not bui.app.classic.accounts.have_pro_options()
|
||||
@ -443,7 +452,8 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
SoundtrackEditWindow(
|
||||
existing_soundtrack=self._selected_soundtrack
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _get_soundtrack_display_name(self, soundtrack: str) -> bui.Lstr:
|
||||
|
||||
@ -351,7 +351,8 @@ class SoundtrackEditWindow(bui.Window):
|
||||
soundtrack[musictype] = entry
|
||||
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
cls(state, transition='in_left').get_root_widget()
|
||||
cls(state, transition='in_left').get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
|
||||
def _get_entry(
|
||||
@ -359,6 +360,11 @@ class SoundtrackEditWindow(bui.Window):
|
||||
) -> 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:
|
||||
return
|
||||
|
||||
if selection_target_name != '':
|
||||
selection_target_name = "'" + selection_target_name + "'"
|
||||
state = {
|
||||
@ -375,7 +381,8 @@ class SoundtrackEditWindow(bui.Window):
|
||||
entry,
|
||||
selection_target_name,
|
||||
)
|
||||
.get_root_widget()
|
||||
.get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _test(self, song_type: bs.MusicType) -> None:
|
||||
@ -422,6 +429,10 @@ class SoundtrackEditWindow(bui.Window):
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.soundtrack import browser as stb
|
||||
|
||||
# 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
|
||||
music = bui.app.classic.music
|
||||
|
||||
@ -429,12 +440,17 @@ class SoundtrackEditWindow(bui.Window):
|
||||
music.set_music_play_mode(bui.app.classic.MusicPlayMode.REGULAR)
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
stb.SoundtrackBrowserWindow(transition='in_left').get_root_widget()
|
||||
stb.SoundtrackBrowserWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_it(self) -> None:
|
||||
from bauiv1lib.soundtrack import browser as stb
|
||||
|
||||
# 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
|
||||
music = bui.app.classic.music
|
||||
cfg = bui.app.config
|
||||
@ -483,7 +499,8 @@ class SoundtrackEditWindow(bui.Window):
|
||||
)
|
||||
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
stb.SoundtrackBrowserWindow(transition='in_left').get_root_widget()
|
||||
stb.SoundtrackBrowserWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_it_with_sound(self) -> None:
|
||||
|
||||
@ -166,6 +166,10 @@ class SoundtrackEntryTypeSelectWindow(bui.Window):
|
||||
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:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
current_playlist_entry: str | None
|
||||
@ -181,7 +185,8 @@ class SoundtrackEntryTypeSelectWindow(bui.Window):
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MacMusicAppPlaylistSelectWindow(
|
||||
self._callback, current_playlist_entry, self._current_entry
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _on_music_file_press(self) -> None:
|
||||
@ -189,6 +194,10 @@ class SoundtrackEntryTypeSelectWindow(bui.Window):
|
||||
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:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
base_path = android_get_external_files_dir()
|
||||
assert bui.app.classic is not None
|
||||
@ -201,13 +210,18 @@ class SoundtrackEntryTypeSelectWindow(bui.Window):
|
||||
OSMusicPlayer.get_valid_music_file_extensions()
|
||||
),
|
||||
allow_folders=False,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
base_path = android_get_external_files_dir()
|
||||
assert bui.app.classic is not None
|
||||
@ -218,7 +232,8 @@ class SoundtrackEntryTypeSelectWindow(bui.Window):
|
||||
show_base_path=False,
|
||||
valid_file_extensions=[],
|
||||
allow_folders=True,
|
||||
).get_root_widget()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _music_file_selector_cb(self, result: str | None) -> None:
|
||||
|
||||
@ -1329,6 +1329,10 @@ class StoreBrowserWindow(bui.Window):
|
||||
from bauiv1lib.account import show_sign_in_prompt
|
||||
from bauiv1lib.getcurrency import GetCurrencyWindow
|
||||
|
||||
# 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
|
||||
|
||||
@ -1343,13 +1347,19 @@ class StoreBrowserWindow(bui.Window):
|
||||
).get_root_widget()
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(window)
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
window, from_window=self._root_widget
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
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:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
@ -1358,11 +1368,13 @@ class StoreBrowserWindow(bui.Window):
|
||||
assert bui.app.classic is not None
|
||||
if self._back_location == 'CoopBrowserWindow':
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(transition='in_left').get_root_widget()
|
||||
CoopBrowserWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
else:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
if self._on_close_call is not None:
|
||||
self._on_close_call()
|
||||
|
||||
@ -663,11 +663,16 @@ class WatchWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
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:
|
||||
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_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget()
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -615,7 +615,7 @@ void Graphics::FadeScreen(bool to, millisecs_t time, PyObject* endcall) {
|
||||
Log(LogLevel::kWarning,
|
||||
"2 fades overlapping; running first fade-end-call early.");
|
||||
}
|
||||
fade_end_call_->ScheduleOnce();
|
||||
fade_end_call_->Schedule();
|
||||
fade_end_call_.Clear();
|
||||
}
|
||||
set_fade_start_on_next_draw_ = true;
|
||||
@ -1021,7 +1021,7 @@ void Graphics::DrawFades(FrameDef* frame_def) {
|
||||
} else {
|
||||
fade_ = 0;
|
||||
if (!was_done && fade_end_call_.Exists()) {
|
||||
fade_end_call_->ScheduleOnce();
|
||||
fade_end_call_->Schedule();
|
||||
fade_end_call_.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ static auto PyPushCall(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
if (!g_base->InLogicThread()) {
|
||||
throw Exception("You must use from_other_thread mode.");
|
||||
}
|
||||
Object::New<PythonContextCall>(call_obj)->ScheduleOnce();
|
||||
Object::New<PythonContextCall>(call_obj)->Schedule();
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
|
||||
@ -125,83 +125,45 @@ void PythonContextCall::Schedule() {
|
||||
Object::Ref<PythonContextCall> ref(this);
|
||||
|
||||
assert(base::g_base);
|
||||
schedule_count_++;
|
||||
base::g_base->logic->event_loop()->PushCall([ref] {
|
||||
assert(ref.Exists());
|
||||
ref->schedule_count_--;
|
||||
assert(ref->schedule_count_ >= 0);
|
||||
ref->Run();
|
||||
});
|
||||
}
|
||||
void PythonContextCall::ScheduleOnce() {
|
||||
if (schedule_count_ > 0) {
|
||||
return;
|
||||
}
|
||||
Schedule();
|
||||
}
|
||||
|
||||
void PythonContextCall::Schedule(const PythonRef& args) {
|
||||
// Since we're mucking with Object::Refs, need to limit to logic thread.
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
Object::Ref<PythonContextCall> ref(this);
|
||||
assert(base::g_base);
|
||||
schedule_count_++;
|
||||
base::g_base->logic->event_loop()->PushCall([ref, args] {
|
||||
assert(ref.Exists());
|
||||
ref->schedule_count_--;
|
||||
assert(ref->schedule_count_ >= 0);
|
||||
ref->Run(args);
|
||||
});
|
||||
}
|
||||
void PythonContextCall::ScheduleOnce(const PythonRef& args) {
|
||||
if (schedule_count_ > 0) {
|
||||
return;
|
||||
}
|
||||
Schedule(args);
|
||||
}
|
||||
|
||||
void PythonContextCall::ScheduleWeak() {
|
||||
// Since we're mucking with Object::WeakRefs, need to limit to logic thread.
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
Object::WeakRef<PythonContextCall> ref(this);
|
||||
assert(base::g_base);
|
||||
schedule_count_++;
|
||||
base::g_base->logic->event_loop()->PushCall([ref] {
|
||||
if (auto* call = ref.Get()) {
|
||||
call->schedule_count_--;
|
||||
assert(call->schedule_count_ >= 0);
|
||||
call->Run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PythonContextCall::ScheduleWeakOnce() {
|
||||
if (schedule_count_ > 0) {
|
||||
return;
|
||||
}
|
||||
ScheduleWeak();
|
||||
}
|
||||
|
||||
void PythonContextCall::ScheduleWeak(const PythonRef& args) {
|
||||
// Since we're mucking with Object::WeakRefs, need to limit to logic thread.
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
Object::WeakRef<PythonContextCall> ref(this);
|
||||
assert(base::g_base);
|
||||
schedule_count_++;
|
||||
base::g_base->logic->event_loop()->PushCall([ref, args] {
|
||||
if (auto* call = ref.Get()) {
|
||||
call->schedule_count_--;
|
||||
assert(call->schedule_count_ >= 0);
|
||||
call->Run(args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PythonContextCall::ScheduleWeakOnce(const PythonRef& args) {
|
||||
if (schedule_count_ > 0) {
|
||||
return;
|
||||
}
|
||||
ScheduleWeak(args);
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -42,56 +42,26 @@ class PythonContextCall : public Object {
|
||||
/// context_ref-call is guaranteed to exist until run.
|
||||
void Schedule();
|
||||
|
||||
/// Schedule only if this instance is not already scheduled. Generally a
|
||||
/// good idea unless you know you need multiple runs scheduled. Avoids
|
||||
/// problems such as UIs expecting to be activated only once getting
|
||||
/// activated twice due to two simultenous key presses.
|
||||
void ScheduleOnce();
|
||||
|
||||
/// Run in an upcoming cycle of the logic thread with provided args. Must
|
||||
/// be called from the logic thread. This form creates a strong-reference
|
||||
/// so the context_ref-call is guaranteed to exist until run.
|
||||
void Schedule(const PythonRef& args);
|
||||
|
||||
/// Schedule only if this instance is not already scheduled. Generally a
|
||||
/// good idea unless you know you need multiple runs scheduled. Avoids
|
||||
/// problems such as UIs expecting to be activated only once getting
|
||||
/// activated twice due to two simultenous key presses.
|
||||
void ScheduleOnce(const PythonRef& args);
|
||||
|
||||
/// Run in an upcoming cycle of the logic thread. Must be called from the
|
||||
/// logic thread. This form creates a weak-reference and is a no-op if the
|
||||
/// context_ref-call is destroyed before its scheduled run.
|
||||
void ScheduleWeak();
|
||||
|
||||
/// Schedule weakly only if this instance is not already scheduled.
|
||||
/// Generally a good idea unless you know you need multiple runs
|
||||
/// scheduled. Avoids problems such as UIs expecting to be activated only
|
||||
/// once getting activated twice due to two simultenous key presses.
|
||||
void ScheduleWeakOnce();
|
||||
|
||||
/// Run in an upcoming cycle of the logic thread with provided args. Must
|
||||
/// be called from the logic thread. This form creates a weak-reference
|
||||
/// and is a no-op if the context_ref-call is destroyed before its
|
||||
/// scheduled run.
|
||||
void ScheduleWeak(const PythonRef& args);
|
||||
|
||||
/// Schedule weakly only if this instance is not already scheduled.
|
||||
/// Generally a good idea unless you know you need multiple runs
|
||||
/// scheduled. Avoids problems such as UIs expecting to be activated only
|
||||
/// once getting activated twice due to two simultenous key presses.
|
||||
void ScheduleWeakOnce(const PythonRef& args);
|
||||
|
||||
auto IsScheduled() const {
|
||||
assert(g_base->InLogicThread());
|
||||
return schedule_count_ > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void GetTrace(); // we try to grab basic trace info
|
||||
|
||||
int line_{};
|
||||
int schedule_count_{};
|
||||
bool dead_{};
|
||||
std::string file_loc_;
|
||||
PythonRef object_;
|
||||
|
||||
@ -208,7 +208,7 @@ auto PythonClassSessionPlayer::tp_getattro(PythonClassSessionPlayer* self,
|
||||
PyObject* attr) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
|
||||
assert(g_base->InLogicThread());
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
|
||||
// Assuming this will always be a str?
|
||||
assert(PyUnicode_Check(attr));
|
||||
@ -327,6 +327,9 @@ auto PythonClassSessionPlayer::tp_setattro(PythonClassSessionPlayer* self,
|
||||
PyObject* attr, PyObject* val)
|
||||
-> int {
|
||||
BA_PYTHON_TRY;
|
||||
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
|
||||
// Assuming this will always be a str?
|
||||
assert(PyUnicode_Check(attr));
|
||||
const char* s = PyUnicode_AsUTF8(attr);
|
||||
|
||||
@ -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 = 21636;
|
||||
const int kEngineBuildNumber = 21639;
|
||||
const char* kEngineVersion = "1.7.30";
|
||||
const int kEngineApiVersion = 8;
|
||||
|
||||
|
||||
@ -17,6 +17,12 @@ auto PythonClassWidget::nb_bool(PythonClassWidget* self) -> int {
|
||||
|
||||
PyNumberMethods PythonClassWidget::as_number_;
|
||||
|
||||
// Attrs we expose through our custom getattr/setattr.
|
||||
#define ATTR_TRANSITIONING_OUT "transitioning_out"
|
||||
|
||||
// The set we expose via dir().
|
||||
static const char* extra_dir_attrs[] = {ATTR_TRANSITIONING_OUT, nullptr};
|
||||
|
||||
auto PythonClassWidget::type_name() -> const char* { return "Widget"; }
|
||||
|
||||
void PythonClassWidget::SetupType(PyTypeObject* cls) {
|
||||
@ -24,6 +30,9 @@ void PythonClassWidget::SetupType(PyTypeObject* cls) {
|
||||
// Fully qualified type path we will be exposed as:
|
||||
cls->tp_name = "bauiv1.Widget";
|
||||
cls->tp_basicsize = sizeof(PythonClassWidget);
|
||||
|
||||
// clang-format off
|
||||
|
||||
cls->tp_doc =
|
||||
"Internal type for low level UI elements; buttons, windows, etc.\n"
|
||||
"\n"
|
||||
@ -31,11 +40,22 @@ void PythonClassWidget::SetupType(PyTypeObject* cls) {
|
||||
"\n"
|
||||
"This class represents a weak reference to a widget object\n"
|
||||
"in the internal C++ layer. Currently, functions such as\n"
|
||||
"babase.buttonwidget() must be used to instantiate or edit these.";
|
||||
"babase.buttonwidget() must be used to instantiate or edit these.\n"
|
||||
"Attributes:\n"
|
||||
" " ATTR_TRANSITIONING_OUT " (bool):\n"
|
||||
" Whether this widget is in the process of dying (read only).\n"
|
||||
"\n"
|
||||
" It can be useful to check this on a window's root widget to\n"
|
||||
" prevent multiple window actions from firing simultaneously,\n"
|
||||
" potentially leaving the UI in a broken state.\n";
|
||||
|
||||
// clang-format on
|
||||
|
||||
cls->tp_new = tp_new;
|
||||
cls->tp_dealloc = (destructor)tp_dealloc;
|
||||
cls->tp_repr = (reprfunc)tp_repr;
|
||||
cls->tp_methods = tp_methods;
|
||||
cls->tp_getattro = (getattrofunc)tp_getattro;
|
||||
|
||||
// we provide number methods only for bool functionality
|
||||
memset(&as_number_, 0, sizeof(as_number_));
|
||||
@ -44,7 +64,7 @@ void PythonClassWidget::SetupType(PyTypeObject* cls) {
|
||||
}
|
||||
|
||||
auto PythonClassWidget::Create(Widget* widget) -> PyObject* {
|
||||
// Make sure we only have one python ref per widget.
|
||||
// Make sure we only have one Python ref per Widget.
|
||||
if (widget) {
|
||||
assert(!widget->has_py_ref());
|
||||
}
|
||||
@ -62,10 +82,56 @@ auto PythonClassWidget::Create(Widget* widget) -> PyObject* {
|
||||
|
||||
auto PythonClassWidget::GetWidget() const -> Widget* {
|
||||
Widget* w = widget_->Get();
|
||||
if (!w) throw Exception("Invalid widget");
|
||||
if (!w) {
|
||||
throw Exception("Invalid Widget", PyExcType::kReference);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
auto PythonClassWidget::tp_getattro(PythonClassWidget* self, PyObject* attr)
|
||||
-> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
|
||||
// Assuming this will always be a str?
|
||||
assert(PyUnicode_Check(attr));
|
||||
|
||||
const char* s = PyUnicode_AsUTF8(attr);
|
||||
if (!strcmp(s, ATTR_TRANSITIONING_OUT)) {
|
||||
Widget* w = self->widget_->Get();
|
||||
if (!w) {
|
||||
throw Exception("Invalid Widget", PyExcType::kReference);
|
||||
}
|
||||
if (w->IsTransitioningOut()) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
// Fall back to generic behavior.
|
||||
PyObject* val;
|
||||
val = PyObject_GenericGetAttr(reinterpret_cast<PyObject*>(self), attr);
|
||||
return val;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
auto PythonClassWidget::tp_setattro(PythonClassWidget* self, PyObject* attr,
|
||||
PyObject* val) -> int {
|
||||
BA_PYTHON_TRY;
|
||||
|
||||
BA_PRECONDITION(g_base->InLogicThread());
|
||||
|
||||
// Assuming this will always be a str?
|
||||
assert(PyUnicode_Check(attr));
|
||||
const char* s = PyUnicode_AsUTF8(attr);
|
||||
|
||||
throw Exception("Attr '" + std::string(PyUnicode_AsUTF8(attr))
|
||||
+ "' is not settable on SessionPlayer objects.",
|
||||
PyExcType::kAttribute);
|
||||
BA_PYTHON_INT_CATCH;
|
||||
}
|
||||
|
||||
auto PythonClassWidget::tp_repr(PythonClassWidget* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
Widget* w = self->widget_->Get();
|
||||
@ -96,8 +162,8 @@ auto PythonClassWidget::tp_new(PyTypeObject* type, PyObject* args,
|
||||
|
||||
void PythonClassWidget::tp_dealloc(PythonClassWidget* self) {
|
||||
BA_PYTHON_TRY;
|
||||
// these have to be destructed in the logic thread - send them along to it if
|
||||
// need be
|
||||
// these have to be destructed in the logic thread - send them along to it
|
||||
// if need be
|
||||
if (!g_base->InLogicThread()) {
|
||||
Object::WeakRef<Widget>* w = self->widget_;
|
||||
g_base->logic->event_loop()->PushCall([w] { delete w; });
|
||||
|
||||
@ -26,6 +26,9 @@ class PythonClassWidget : public PythonClass {
|
||||
static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds)
|
||||
-> PyObject*;
|
||||
static void tp_dealloc(PythonClassWidget* self);
|
||||
static auto tp_getattro(PythonClassWidget* self, PyObject* attr) -> PyObject*;
|
||||
static auto tp_setattro(PythonClassWidget* self, PyObject* attr,
|
||||
PyObject* val) -> int;
|
||||
static auto Exists(PythonClassWidget* self) -> PyObject*;
|
||||
static auto GetWidgetType(PythonClassWidget* self) -> PyObject*;
|
||||
static auto Activate(PythonClassWidget* self) -> PyObject*;
|
||||
|
||||
@ -1219,17 +1219,17 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
if (transition_obj != Py_None) {
|
||||
std::string t = Python::GetPyString(transition_obj);
|
||||
if (t == "in_left")
|
||||
widget->SetTransition(ContainerWidget::TRANSITION_IN_LEFT);
|
||||
widget->SetTransition(ContainerWidget::TransitionType::kInLeft);
|
||||
else if (t == "in_right")
|
||||
widget->SetTransition(ContainerWidget::TRANSITION_IN_RIGHT);
|
||||
widget->SetTransition(ContainerWidget::TransitionType::kInRight);
|
||||
else if (t == "out_left")
|
||||
widget->SetTransition(ContainerWidget::TRANSITION_OUT_LEFT);
|
||||
widget->SetTransition(ContainerWidget::TransitionType::kOutLeft);
|
||||
else if (t == "out_right")
|
||||
widget->SetTransition(ContainerWidget::TRANSITION_OUT_RIGHT);
|
||||
widget->SetTransition(ContainerWidget::TransitionType::kOutRight);
|
||||
else if (t == "in_scale")
|
||||
widget->SetTransition(ContainerWidget::TRANSITION_IN_SCALE);
|
||||
widget->SetTransition(ContainerWidget::TransitionType::kInScale);
|
||||
else if (t == "out_scale")
|
||||
widget->SetTransition(ContainerWidget::TRANSITION_OUT_SCALE);
|
||||
widget->SetTransition(ContainerWidget::TransitionType::kOutScale);
|
||||
}
|
||||
|
||||
if (cancel_button_obj != Py_None) {
|
||||
|
||||
@ -115,7 +115,7 @@ void UIV1Python::InvokeStringEditor(PyObject* string_edit_adapter_instance) {
|
||||
PythonRef::kSteal);
|
||||
Object::New<base::PythonContextCall>(
|
||||
objs().Get(ObjID::kOnScreenKeyboardClass))
|
||||
->ScheduleOnce(args);
|
||||
->Schedule(args);
|
||||
}
|
||||
|
||||
void UIV1Python::LaunchStringEditOld(TextWidget* w) {
|
||||
@ -131,7 +131,7 @@ void UIV1Python::LaunchStringEditOld(TextWidget* w) {
|
||||
PythonRef::kSteal);
|
||||
Object::New<base::PythonContextCall>(
|
||||
objs().Get(ObjID::kOnScreenKeyboardClass))
|
||||
->ScheduleOnce(args);
|
||||
->Schedule(args);
|
||||
}
|
||||
|
||||
void UIV1Python::InvokeQuitWindow(QuitType quit_type) {
|
||||
|
||||
@ -39,6 +39,7 @@ class UIV1Python {
|
||||
kQuitWindowCall,
|
||||
kDeviceMenuPressCall,
|
||||
kShowURLWindowCall,
|
||||
kDoubleTransitionOutWarningCall,
|
||||
kTextWidgetStringEditAdapterClass,
|
||||
kLast // Sentinel; must be at end.
|
||||
};
|
||||
|
||||
@ -562,7 +562,7 @@ void ButtonWidget::DoActivate(bool is_repeat) {
|
||||
if (auto* call = on_activate_call_.Get()) {
|
||||
// Call this in the next cycle (don't want to risk mucking with UI from
|
||||
// within a UI loop.)
|
||||
call->ScheduleWeakOnce();
|
||||
call->ScheduleWeak();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ void CheckBoxWidget::Activate() {
|
||||
|
||||
// Call this in the next cycle (don't want to risk mucking with UI from
|
||||
// within a UI loop)
|
||||
call->ScheduleWeakOnce(args);
|
||||
call->ScheduleWeak(args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,12 +271,13 @@ auto CheckBoxWidget::HandleMessage(const base::WidgetMessage& m) -> bool {
|
||||
float x = m.fval1;
|
||||
float y = m.fval2;
|
||||
bool claimed = (m.fval3 > 0.0f);
|
||||
if (claimed)
|
||||
if (claimed) {
|
||||
mouse_over_ = false;
|
||||
else
|
||||
} else {
|
||||
mouse_over_ =
|
||||
((x >= (-left_overlap)) && (x < (width_ + right_overlap))
|
||||
&& (y >= (-bottom_overlap)) && (y < (height_ + top_overlap)));
|
||||
}
|
||||
return mouse_over_;
|
||||
}
|
||||
case base::WidgetMessage::Type::kMouseDown: {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "ballistica/shared/generic/utils.h"
|
||||
#include "ballistica/shared/math/random.h"
|
||||
#include "ballistica/shared/python/python.h"
|
||||
#include "ballistica/ui_v1/python/ui_v1_python.h"
|
||||
#include "ballistica/ui_v1/widget/button_widget.h"
|
||||
#include "ballistica/ui_v1/widget/root_widget.h"
|
||||
#include "ballistica/ui_v1/widget/stack_widget.h"
|
||||
@ -347,7 +348,7 @@ auto ContainerWidget::HandleMessage(const base::WidgetMessage& m) -> bool {
|
||||
|
||||
// Call this in the next cycle (don't wanna risk mucking with UI from
|
||||
// within a UI loop).
|
||||
call->ScheduleWeakOnce();
|
||||
call->ScheduleWeak();
|
||||
} else {
|
||||
OnCancelCustom();
|
||||
}
|
||||
@ -631,7 +632,7 @@ auto ContainerWidget::HandleMessage(const base::WidgetMessage& m) -> bool {
|
||||
if (!claimed && on_outside_click_call_.Exists()) {
|
||||
// Call this in the next cycle (don't wanna risk mucking with UI from
|
||||
// within a UI loop).
|
||||
on_outside_click_call_->ScheduleWeakOnce();
|
||||
on_outside_click_call_->ScheduleWeak();
|
||||
}
|
||||
|
||||
// Always claim if they want.
|
||||
@ -793,7 +794,7 @@ void ContainerWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
|
||||
bg_dirty_ = true;
|
||||
|
||||
if (!draw_transparent) {
|
||||
if (transition_type_ == TRANSITION_IN_SCALE) {
|
||||
if (transition_type_ == TransitionType::kInScale) {
|
||||
if (net_time - dynamics_update_time_millisecs_ > 1000)
|
||||
dynamics_update_time_millisecs_ = net_time - 1000;
|
||||
while (net_time - dynamics_update_time_millisecs_ > 5) {
|
||||
@ -808,7 +809,7 @@ void ContainerWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
|
||||
transitioning_ = false;
|
||||
}
|
||||
}
|
||||
} else if (transition_type_ == TRANSITION_OUT_SCALE) {
|
||||
} else if (transition_type_ == TransitionType::kOutScale) {
|
||||
if (net_time - dynamics_update_time_millisecs_ > 1000)
|
||||
dynamics_update_time_millisecs_ = net_time - 1000;
|
||||
while (net_time - dynamics_update_time_millisecs_ > 5) {
|
||||
@ -908,8 +909,8 @@ void ContainerWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
|
||||
|
||||
// If we're scaling in or out, update our transition offset
|
||||
// (so we can zoom from a point somewhere else on screen).
|
||||
if (transition_type_ == TRANSITION_IN_SCALE
|
||||
|| transition_type_ == TRANSITION_OUT_SCALE) {
|
||||
if (transition_type_ == TransitionType::kInScale
|
||||
|| transition_type_ == TransitionType::kOutScale) {
|
||||
// Add a fudge factor since our scale point isn't exactly in our center.
|
||||
// :-(
|
||||
float xdiff = scale_origin_stack_offset_x_ - stack_offset_x()
|
||||
@ -1071,7 +1072,7 @@ void ContainerWidget::Activate() {
|
||||
if (auto* call = on_activate_call_.Get()) {
|
||||
// Call this in the next cycle (don't wanna risk mucking with UI from within
|
||||
// a UI loop).
|
||||
call->ScheduleWeakOnce();
|
||||
call->ScheduleWeak();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1156,8 +1157,23 @@ void ContainerWidget::SetStartButton(ButtonWidget* button) {
|
||||
button->set_icon_type(ButtonWidget::IconType::kStart);
|
||||
}
|
||||
|
||||
static auto _IsTransitionOut(ContainerWidget::TransitionType type) {
|
||||
switch (type) {
|
||||
case ContainerWidget::TransitionType::kUnset:
|
||||
case ContainerWidget::TransitionType::kInLeft:
|
||||
case ContainerWidget::TransitionType::kInRight:
|
||||
case ContainerWidget::TransitionType::kInScale:
|
||||
return false;
|
||||
case ContainerWidget::TransitionType::kOutLeft:
|
||||
case ContainerWidget::TransitionType::kOutRight:
|
||||
case ContainerWidget::TransitionType::kOutScale:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ContainerWidget::SetTransition(TransitionType t) {
|
||||
BA_DEBUG_UI_READ_LOCK;
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
bg_dirty_ = glow_dirty_ = true;
|
||||
ContainerWidget* parent = parent_widget();
|
||||
@ -1167,17 +1183,26 @@ void ContainerWidget::SetTransition(TransitionType t) {
|
||||
parent->CheckLayout();
|
||||
auto display_time_millisecs =
|
||||
static_cast<millisecs_t>(g_base->logic->display_time() * 1000.0);
|
||||
|
||||
// Warn if setting out-transition twice. This likely means a window is
|
||||
// switching to another window twice which can leave the UI broken.
|
||||
if (_IsTransitionOut(transition_type_) && _IsTransitionOut(t)) {
|
||||
g_ui_v1->python->objs()
|
||||
.Get(UIV1Python::ObjID::kDoubleTransitionOutWarningCall)
|
||||
.Call();
|
||||
}
|
||||
|
||||
transition_type_ = t;
|
||||
|
||||
// Scale transitions are simpler.
|
||||
if (t == TRANSITION_IN_SCALE) {
|
||||
if (t == TransitionType::kInScale) {
|
||||
transition_start_time_ = display_time_millisecs;
|
||||
dynamics_update_time_millisecs_ = display_time_millisecs;
|
||||
transitioning_ = true;
|
||||
transitioning_out_ = false;
|
||||
transition_scale_ = 0.0f;
|
||||
d_transition_scale_ = 0.0f;
|
||||
} else if (t == TRANSITION_OUT_SCALE) {
|
||||
} else if (t == TransitionType::kOutScale) {
|
||||
transition_start_time_ = display_time_millisecs;
|
||||
dynamics_update_time_millisecs_ = display_time_millisecs;
|
||||
transitioning_ = true;
|
||||
@ -1195,7 +1220,7 @@ void ContainerWidget::SetTransition(TransitionType t) {
|
||||
|
||||
// In case we're mid-transition, this avoids hitches.
|
||||
float y_offs = 2.0f;
|
||||
if (t == TRANSITION_IN_LEFT) {
|
||||
if (t == TransitionType::kInLeft) {
|
||||
transition_start_time_ = display_time_millisecs;
|
||||
transition_start_offset_ = screen_min_x - width_ - 100;
|
||||
transition_offset_x_smoothed_ = transition_start_offset_;
|
||||
@ -1204,7 +1229,7 @@ void ContainerWidget::SetTransition(TransitionType t) {
|
||||
transitioning_ = true;
|
||||
dynamics_update_time_millisecs_ = display_time_millisecs;
|
||||
transitioning_out_ = false;
|
||||
} else if (t == TRANSITION_IN_RIGHT) {
|
||||
} else if (t == TransitionType::kInRight) {
|
||||
transition_start_time_ = display_time_millisecs;
|
||||
transition_start_offset_ = screen_max_x + 100;
|
||||
transition_offset_x_smoothed_ = transition_start_offset_;
|
||||
@ -1213,7 +1238,7 @@ void ContainerWidget::SetTransition(TransitionType t) {
|
||||
transitioning_ = true;
|
||||
dynamics_update_time_millisecs_ = display_time_millisecs;
|
||||
transitioning_out_ = false;
|
||||
} else if (t == TRANSITION_OUT_LEFT) {
|
||||
} else if (t == TransitionType::kOutLeft) {
|
||||
transition_start_time_ = display_time_millisecs;
|
||||
transition_start_offset_ = transition_offset_x_;
|
||||
transition_target_offset_ = -2.0f * (screen_max_x - screen_min_x);
|
||||
@ -1223,7 +1248,7 @@ void ContainerWidget::SetTransition(TransitionType t) {
|
||||
dynamics_update_time_millisecs_ = display_time_millisecs;
|
||||
transitioning_out_ = true;
|
||||
ignore_input_ = true;
|
||||
} else if (t == TRANSITION_OUT_RIGHT) {
|
||||
} else if (t == TransitionType::kOutRight) {
|
||||
transition_start_time_ = display_time_millisecs;
|
||||
transition_start_offset_ = transition_offset_x_;
|
||||
transition_target_offset_ = 2.0f * (screen_max_x - screen_min_x);
|
||||
@ -1279,8 +1304,9 @@ void ContainerWidget::DeleteWidget(Widget* w) {
|
||||
|
||||
assert(found);
|
||||
|
||||
// Special case: if we're the overlay stack and we've deleted our last widget,
|
||||
// try to reselect whatever was last selected before the overlay stack.
|
||||
// Special case: if we're the overlay stack and we've deleted our last
|
||||
// widget, try to reselect whatever was last selected before the overlay
|
||||
// stack.
|
||||
if (is_overlay_window_stack_) {
|
||||
if (widgets_.empty()) {
|
||||
// Eww this logic should be in some sort of controller.
|
||||
@ -1298,8 +1324,9 @@ void ContainerWidget::DeleteWidget(Widget* w) {
|
||||
if ((**i).IsSelectable()) {
|
||||
// A change on the main or overlay window stack changes the global
|
||||
// selection (unless its on the main window stack and there's already
|
||||
// something on the overlay stack) in all other cases we just shift our
|
||||
// direct selected child (which may not affect the global selection).
|
||||
// something on the overlay stack) in all other cases we just shift
|
||||
// our direct selected child (which may not affect the global
|
||||
// selection).
|
||||
if (is_window_stack_
|
||||
&& (is_overlay_window_stack_
|
||||
|| !g_ui_v1->root_widget()
|
||||
@ -1322,8 +1349,8 @@ void ContainerWidget::DeleteWidget(Widget* w) {
|
||||
}
|
||||
|
||||
auto ContainerWidget::GetTopmostToolbarInfluencingWidget() -> Widget* {
|
||||
// Look for the first window that is accepting input (filters out windows that
|
||||
// are transitioning out) and also set to affect the toolbar state.
|
||||
// Look for the first window that is accepting input (filters out windows
|
||||
// that are transitioning out) and also set to affect the toolbar state.
|
||||
for (auto w = widgets_.rbegin(); w != widgets_.rend(); ++w) {
|
||||
if ((**w).IsAcceptingInput()
|
||||
&& (**w).toolbar_visibility() != ToolbarVisibility::kInherit) {
|
||||
@ -1438,9 +1465,8 @@ void ContainerWidget::SetSelected(bool s, SelectionCause cause) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if we're being deselected and we have a selected child, tell them they're
|
||||
// deselected
|
||||
// if (selected_widget_) {
|
||||
// if we're being deselected and we have a selected child, tell them
|
||||
// they're deselected if (selected_widget_) {
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -1583,8 +1609,8 @@ void ContainerWidget::SelectDownWidget() {
|
||||
selected_widget_->GetCenter(&our_x, &our_y);
|
||||
w = GetClosestDownWidget(our_x, our_y, selected_widget_);
|
||||
if (!w) {
|
||||
// If we found no viable children and we're under the main window stack,
|
||||
// see if we should pass focus to a toolbar widget.
|
||||
// If we found no viable children and we're under the main window
|
||||
// stack, see if we should pass focus to a toolbar widget.
|
||||
if (IsInMainStack()) {
|
||||
float x = our_x;
|
||||
float y = our_y;
|
||||
@ -1712,7 +1738,8 @@ void ContainerWidget::SelectLeftWidget() {
|
||||
float our_x, our_y;
|
||||
selected_widget_->GetCenter(&our_x, &our_y);
|
||||
w = GetClosestLeftWidget(our_x, our_y, selected_widget_);
|
||||
// When we find no viable targets for an autoselect widget we do nothing.
|
||||
// When we find no viable targets for an autoselect widget we do
|
||||
// nothing.
|
||||
if (!w) {
|
||||
return;
|
||||
}
|
||||
@ -1843,8 +1870,8 @@ void ContainerWidget::SelectNextWidget() {
|
||||
return;
|
||||
} else if (selected_widget_
|
||||
== nullptr) { // NOLINT(bugprone-branch-clone)
|
||||
// We've got no selection and we've scanned the whole list to no avail,
|
||||
// fail.
|
||||
// We've got no selection and we've scanned the whole list to no
|
||||
// avail, fail.
|
||||
PrintExitListInstructions(old_last_prev_next_time);
|
||||
return;
|
||||
} else if (selection_loops()) {
|
||||
@ -1997,4 +2024,8 @@ void ContainerWidget::OnLanguageChange() {
|
||||
}
|
||||
}
|
||||
|
||||
auto ContainerWidget::IsTransitioningOut() const -> bool {
|
||||
return transitioning_out_;
|
||||
}
|
||||
|
||||
} // namespace ballistica::ui_v1
|
||||
|
||||
@ -14,20 +14,21 @@ namespace ballistica::ui_v1 {
|
||||
// Base class for widgets that contain other widgets.
|
||||
class ContainerWidget : public Widget {
|
||||
public:
|
||||
explicit ContainerWidget(float width = 0, float height = 0);
|
||||
explicit ContainerWidget(float width = 0.0f, float height = 0.0f);
|
||||
~ContainerWidget() override;
|
||||
|
||||
void Draw(base::RenderPass* pass, bool transparent) override;
|
||||
|
||||
auto HandleMessage(const base::WidgetMessage& m) -> bool override;
|
||||
|
||||
enum TransitionType {
|
||||
TRANSITION_OUT_LEFT,
|
||||
TRANSITION_OUT_RIGHT,
|
||||
TRANSITION_IN_LEFT,
|
||||
TRANSITION_IN_RIGHT,
|
||||
TRANSITION_IN_SCALE,
|
||||
TRANSITION_OUT_SCALE
|
||||
enum class TransitionType {
|
||||
kUnset,
|
||||
kOutLeft,
|
||||
kOutRight,
|
||||
kInLeft,
|
||||
kInRight,
|
||||
kInScale,
|
||||
kOutScale
|
||||
};
|
||||
|
||||
void SetTransition(TransitionType t);
|
||||
@ -49,6 +50,7 @@ class ContainerWidget : public Widget {
|
||||
width_ = w;
|
||||
MarkForUpdate();
|
||||
}
|
||||
|
||||
virtual void SetHeight(float h) {
|
||||
bg_dirty_ = glow_dirty_ = true;
|
||||
height_ = h;
|
||||
@ -67,6 +69,7 @@ class ContainerWidget : public Widget {
|
||||
CheckLayout();
|
||||
return width_;
|
||||
}
|
||||
|
||||
auto GetHeight() -> float override {
|
||||
CheckLayout();
|
||||
return height_;
|
||||
@ -76,8 +79,8 @@ class ContainerWidget : public Widget {
|
||||
|
||||
auto HasKeySelectableChild() const -> bool;
|
||||
|
||||
void set_is_window_stack(bool a) { is_window_stack_ = a; }
|
||||
auto is_window_stack() const -> bool { return is_window_stack_; }
|
||||
void set_is_window_stack(bool a) { is_window_stack_ = a; }
|
||||
|
||||
auto GetChildCount() const -> int {
|
||||
assert(g_base->InLogicThread());
|
||||
@ -167,6 +170,8 @@ class ContainerWidget : public 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; }
|
||||
|
||||
@ -592,7 +592,7 @@ void TextWidget::Activate() {
|
||||
if (auto* call = on_activate_call_.Get()) {
|
||||
// Call this in the next cycle (don't wanna risk mucking with UI from
|
||||
// within a UI loop).
|
||||
call->ScheduleWeakOnce();
|
||||
call->ScheduleWeak();
|
||||
}
|
||||
|
||||
// Bring up an editor if applicable.
|
||||
@ -720,7 +720,7 @@ auto TextWidget::HandleMessage(const base::WidgetMessage& m) -> bool {
|
||||
claimed = true;
|
||||
// Call this in the next cycle (don't wanna risk mucking with UI
|
||||
// from within a UI loop)
|
||||
call->ScheduleWeakOnce();
|
||||
call->ScheduleWeak();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -88,7 +88,7 @@ void Widget::SetSelected(bool s, SelectionCause cause) {
|
||||
if (selected_ && on_select_call_.Exists()) {
|
||||
// Call this in the next cycle (don't wanna risk mucking
|
||||
// with UI from within a UI loop).
|
||||
on_select_call_->ScheduleWeakOnce();
|
||||
on_select_call_->ScheduleWeak();
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,4 +238,6 @@ auto Widget::IsAcceptingInput() const -> bool { return true; }
|
||||
|
||||
void Widget::Activate() {}
|
||||
|
||||
auto Widget::IsTransitioningOut() const -> bool { return false; }
|
||||
|
||||
} // namespace ballistica::ui_v1
|
||||
|
||||
@ -46,7 +46,8 @@ class Widget : public Object {
|
||||
// Whether the widget (or its children) is selectable in any way.
|
||||
virtual auto IsSelectable() -> bool;
|
||||
|
||||
// Whether the widget can be selected by default with direction/tab presses.
|
||||
// Whether the widget can be selected by default with direction/tab
|
||||
// presses.
|
||||
virtual auto IsSelectableViaKeys() -> bool;
|
||||
|
||||
// Is the widget currently accepting input?
|
||||
@ -83,8 +84,8 @@ class Widget : public Object {
|
||||
// If this widget is in a container, return it.
|
||||
auto parent_widget() const -> ContainerWidget* { return parent_widget_; }
|
||||
|
||||
// Return the container_widget containing this widget, or the owner-widget if
|
||||
// there is no parent.
|
||||
// Return the container_widget containing this widget, or the owner-widget
|
||||
// if there is no parent.
|
||||
auto GetOwnerWidget() const -> Widget*;
|
||||
|
||||
auto down_widget() const -> Widget* { return down_widget_.Get(); }
|
||||
@ -116,25 +117,23 @@ class Widget : public Object {
|
||||
// redirecting them to transient per-window stuff).
|
||||
void set_neighbors_locked(bool locked) { neighbors_locked_ = locked; }
|
||||
|
||||
// Widgets normally draw with a local depth range of 0-1.
|
||||
// It can be useful to limit drawing to a subsection of that region however
|
||||
// (for manually resolving overlap issues with widgets at the same depth,
|
||||
// etc).
|
||||
// Widgets normally draw with a local depth range of 0-1. It can be useful
|
||||
// to limit drawing to a subsection of that region however (for manually
|
||||
// resolving overlap issues with widgets at the same depth, etc).
|
||||
void SetDepthRange(float minDepth, float maxDepth);
|
||||
|
||||
auto depth_range_min() const -> float { return depth_range_min_; }
|
||||
auto depth_range_max() const -> float { return depth_range_max_; }
|
||||
|
||||
// For use by ContainerWidgets.
|
||||
// (we probably should just this functionality to all widgets)
|
||||
// For use by ContainerWidgets (we probably should just add this
|
||||
// functionality to all widgets).
|
||||
void set_parent_widget(ContainerWidget* c) { parent_widget_ = c; }
|
||||
|
||||
auto IsInMainStack() const -> bool;
|
||||
auto IsInOverlayStack() const -> bool;
|
||||
|
||||
// For use when embedding widgets inside others manually.
|
||||
// This will allow proper selection states/etc to trickle down to the
|
||||
// lowest-level child.
|
||||
// For use when embedding widgets inside others manually. This will allow
|
||||
// proper selection states/etc to trickle down to the lowest-level child.
|
||||
void set_owner_widget(Widget* o) { owner_widget_ = o; }
|
||||
virtual auto GetWidgetTypeName() -> std::string { return "widget"; }
|
||||
virtual auto HasChildren() const -> bool { return false; }
|
||||
@ -167,22 +166,25 @@ class Widget : public Object {
|
||||
void ScreenPointToWidget(float* x, float* y) const;
|
||||
void WidgetPointToScreen(float* x, float* y) const;
|
||||
|
||||
// Draw-control parents are used to give one widget some basic visual control
|
||||
// over others, allowing them to inherit things like draw-brightness and tilt
|
||||
// shift (for cases such as images drawn over buttons).
|
||||
// Ideally we'd probably want to extend the parent mechanism for this, but
|
||||
// this works for now.
|
||||
// Draw-control parents are used to give one widget some basic visual
|
||||
// control over others, allowing them to inherit things like
|
||||
// draw-brightness and tilt shift (for cases such as images drawn over
|
||||
// buttons). Ideally we'd probably want to extend the parent mechanism for
|
||||
// this, but this works for now.
|
||||
auto draw_control_parent() const -> Widget* {
|
||||
return draw_control_parent_.Get();
|
||||
}
|
||||
void set_draw_control_parent(Widget* w) { draw_control_parent_ = w; }
|
||||
|
||||
// Can be used to ask link-parents how bright to draw.
|
||||
// Note: make sure the value returned here does not get changed when draw()
|
||||
// is run, since parts of draw-controlled children may query this before
|
||||
// draw() and parts after. (and they need to line up visually)
|
||||
// Can be used to ask link-parents how bright to draw. Note: make sure the
|
||||
// value returned here does not get changed when draw() is run, since
|
||||
// parts of draw-controlled children may query this before draw() and
|
||||
// parts after. (and they need to line up visually)
|
||||
virtual auto GetDrawBrightness(millisecs_t current_time) const -> float;
|
||||
|
||||
/// Is this widget in the process of transitioning out before dying?
|
||||
virtual auto IsTransitioningOut() const -> bool;
|
||||
|
||||
// Extra buffer added around widgets when they are centered-on.
|
||||
void set_show_buffer_top(float b) { show_buffer_top_ = b; }
|
||||
void set_show_buffer_bottom(float b) { show_buffer_bottom_ = b; }
|
||||
@ -206,8 +208,8 @@ class Widget : public Object {
|
||||
|
||||
virtual void OnLanguageChange() {}
|
||||
|
||||
// Primitive janktastic child culling for use by containers.
|
||||
// (should really implement something more proper...)
|
||||
// Primitive janktastic child culling for use by containers (should really
|
||||
// implement something more proper).
|
||||
auto simple_culling_v() const -> float { return simple_culling_v_; }
|
||||
auto simple_culling_h() const -> float { return simple_culling_h_; }
|
||||
auto simple_culling_bottom() const -> float { return simple_culling_bottom_; }
|
||||
@ -224,14 +226,17 @@ class Widget : public Object {
|
||||
private:
|
||||
auto GetPyWidget(bool new_ref) -> PyObject*;
|
||||
virtual void SetSelected(bool s, SelectionCause cause);
|
||||
bool selected_{};
|
||||
bool visible_in_container_{true};
|
||||
bool neighbors_locked_{};
|
||||
bool auto_select_{};
|
||||
ToolbarVisibility toolbar_visibility_{ToolbarVisibility::kMenuMinimalNoBack};
|
||||
float simple_culling_h_{-1.0f};
|
||||
float simple_culling_v_{-1.0f};
|
||||
float simple_culling_left_{};
|
||||
float simple_culling_right_{};
|
||||
float simple_culling_bottom_{};
|
||||
float simple_culling_top_{};
|
||||
ToolbarVisibility toolbar_visibility_{ToolbarVisibility::kMenuMinimalNoBack};
|
||||
PyObject* py_ref_{};
|
||||
float show_buffer_top_{20.0f};
|
||||
float show_buffer_bottom_{20.0f};
|
||||
float show_buffer_left_{20.0f};
|
||||
@ -241,12 +246,9 @@ class Widget : public Object {
|
||||
Object::WeakRef<Widget> up_widget_;
|
||||
Object::WeakRef<Widget> left_widget_;
|
||||
Object::WeakRef<Widget> right_widget_;
|
||||
bool neighbors_locked_{};
|
||||
bool auto_select_{};
|
||||
ContainerWidget* parent_widget_{};
|
||||
PyObject* py_ref_{};
|
||||
Widget* owner_widget_{};
|
||||
bool selected_{};
|
||||
bool visible_in_container_{true};
|
||||
float tx_{};
|
||||
float ty_{};
|
||||
float stack_offset_x_{};
|
||||
|
||||
@ -22,5 +22,6 @@ values = [
|
||||
_hooks.quit_window, # kQuitWindowCall
|
||||
_hooks.device_menu_press, # kDeviceMenuPressCall
|
||||
_hooks.show_url_window, # kShowURLWindowCall
|
||||
_hooks.double_transition_out_warning, # kDoubleTransitionOutWarningCall
|
||||
TextWidgetStringEditAdapter, # kTextWidgetStringEditAdapterClass
|
||||
]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user