Work on type-safe TabRow class

This commit is contained in:
Eric Froemling 2020-10-20 13:59:06 -07:00
parent eba70f0c81
commit 981375f51e
9 changed files with 160 additions and 77 deletions

View File

@ -3932,24 +3932,24 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450", "assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e", "assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/d1/e12c5331256ecffcd7684d6d2963", "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/81/be/dd6f786f096520a5450b96b0efd9",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c5/35/8d811eec1a47f4e70d4b27eb3bf5", "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/14/defa61c54179e1810f8308cac55c",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6f/43/d0f61fb34a76e11b9ebd4334038d", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/89/2d/9c41cd7bba801f79906a397f9b23",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/56/614e09d8ab86355f0d65c1ce76fe", "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/78/bb/4656448316b4b5ff7bc348ede9f2",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/c5/f695953295c2d79dfb01555aea89", "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c0/e0/54ff7942beddb65315194b79da09",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/19/ff1bba3a148b6e0f0823d7d7c7bf", "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/52/1771901e2344bad49238986c80b2",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/dd/d5e4d872192060d46821d6911c13", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2d/d7/e1ffb234f71e715587456fc7cfd8",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/64/58/962c2e707ee66d310848f375796a", "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/88/2ee8c18b63f64425516050c8a304",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/db/58/65c487facba1de6ba8ce65f19f01", "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ac/a2/75427a8ecc1f19d402b58f9014e6",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/40/cb/afd71350fdc9827ca99baab73001", "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d7/d4/4640f90f0ae2d2b98b8fbf099c2f",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f2/05/e9252b68a96ee418da35dd4d2530", "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/95/94/a110e7c8d338d5a6cefe2e975e8b",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bb/a2/e1f5b3f561a08bb09cc3ffb2492f", "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/51/26/638d82bbf9acbfaffd8cfe780671",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/c9/3b04209f599dea8b8ca4be7d3404", "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/c9/3b04209f599dea8b8ca4be7d3404",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/3b/b7b46c3131cff8a40dfaa001af38", "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/3b/b7b46c3131cff8a40dfaa001af38",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/57/40/0c1d88af3ce14e0f8870ab9ac7ad", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/57/40/0c1d88af3ce14e0f8870ab9ac7ad",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8a/72/02b4eddf662001f05f98288d4ad4", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8a/72/02b4eddf662001f05f98288d4ad4",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fc/bc/51529aac7531d1a62cf13eb79153", "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ac/e6/0e2476b60bfa7d3af4e9a2a6db1f",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/7b/de9ce5284627cc77b2fffc354a66", "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f3/81/218f5899da12bcaf1128175e7ef0",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/96/00/78b64146e33ec35dcde9c278328a", "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/84/14/923a2f78920255adffe574b613d6",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6d/25/0e5918fa1eb7285538d14051761c" "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4e/f0/8e6fdd837a08e6daae5bd9e743dc"
} }

View File

@ -29,8 +29,8 @@
<w>achname</w> <w>achname</w>
<w>achs</w> <w>achs</w>
<w>acinstance</w> <w>acinstance</w>
<w>ack</w>
<w>ack'ed</w> <w>ack'ed</w>
<w>ack</w>
<w>acked</w> <w>acked</w>
<w>acks</w> <w>acks</w>
<w>acnt</w> <w>acnt</w>
@ -152,8 +152,8 @@
<w>bacommon</w> <w>bacommon</w>
<w>badguy</w> <w>badguy</w>
<w>bafoundation</w> <w>bafoundation</w>
<w>ballistica</w>
<w>ballistica's</w> <w>ballistica's</w>
<w>ballistica</w>
<w>ballisticacore</w> <w>ballisticacore</w>
<w>ballisticacorecb</w> <w>ballisticacorecb</w>
<w>bamaster</w> <w>bamaster</w>
@ -800,8 +800,8 @@
<w>gamedata</w> <w>gamedata</w>
<w>gameinstance</w> <w>gameinstance</w>
<w>gamemap</w> <w>gamemap</w>
<w>gamepad</w>
<w>gamepad's</w> <w>gamepad's</w>
<w>gamepad</w>
<w>gamepadadvanced</w> <w>gamepadadvanced</w>
<w>gamepads</w> <w>gamepads</w>
<w>gamepadselect</w> <w>gamepadselect</w>
@ -1189,8 +1189,8 @@
<w>lsqlite</w> <w>lsqlite</w>
<w>lssl</w> <w>lssl</w>
<w>lstart</w> <w>lstart</w>
<w>lstr</w>
<w>lstr's</w> <w>lstr's</w>
<w>lstr</w>
<w>lstrs</w> <w>lstrs</w>
<w>lsval</w> <w>lsval</w>
<w>ltex</w> <w>ltex</w>
@ -1823,8 +1823,8 @@
<w>sessionname</w> <w>sessionname</w>
<w>sessionplayer</w> <w>sessionplayer</w>
<w>sessionplayers</w> <w>sessionplayers</w>
<w>sessionteam</w>
<w>sessionteam's</w> <w>sessionteam's</w>
<w>sessionteam</w>
<w>sessionteams</w> <w>sessionteams</w>
<w>sessiontype</w> <w>sessiontype</w>
<w>setactivity</w> <w>setactivity</w>
@ -2009,6 +2009,7 @@
<w>sysconfigdata</w> <w>sysconfigdata</w>
<w>sysctl</w> <w>sysctl</w>
<w>syslogmodule</w> <w>syslogmodule</w>
<w>tabdefs</w>
<w>tabval</w> <w>tabval</w>
<w>tagargs</w> <w>tagargs</w>
<w>tagversion</w> <w>tagversion</w>
@ -2156,8 +2157,8 @@
<w>txtw</w> <w>txtw</w>
<w>typeargs</w> <w>typeargs</w>
<w>typecheck</w> <w>typecheck</w>
<w>typechecker</w>
<w>typechecker's</w> <w>typechecker's</w>
<w>typechecker</w>
<w>typedval</w> <w>typedval</w>
<w>typeshed</w> <w>typeshed</w>
<w>typestr</w> <w>typestr</w>

View File

@ -7,6 +7,14 @@ import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba import _ba
from ba._music import MusicSubsystem
from ba._language import LanguageSubsystem
from ba._ui import UISubsystem
from ba._achievement import AchievementSubsystem
from ba._plugin import PluginSubsystem
from ba._account import AccountSubsystem
from ba._meta import MetadataSubsystem
from ba._ads import AdsSubsystem
if TYPE_CHECKING: if TYPE_CHECKING:
import ba import ba
@ -165,14 +173,6 @@ class App:
the single shared instance. the single shared instance.
""" """
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
from ba._music import MusicSubsystem
from ba._language import LanguageSubsystem
from ba._ui import UISubsystem
from ba._achievement import AchievementSubsystem
from ba._plugin import PluginSubsystem
from ba._account import AccountSubsystem
from ba._meta import MetadataSubsystem
from ba._ads import AdsSubsystem
# Config. # Config.
self.config_file_healthy = False self.config_file_healthy = False

View File

@ -175,6 +175,7 @@ def print_live_object_warnings(when: Any,
from ba._session import Session from ba._session import Session
from ba._actor import Actor from ba._actor import Actor
from ba._activity import Activity from ba._activity import Activity
sessions: List[ba.Session] = [] sessions: List[ba.Session] = []
activities: List[ba.Activity] = [] activities: List[ba.Activity] = []
actors: List[ba.Actor] = [] actors: List[ba.Actor] = []

View File

@ -4,7 +4,8 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from dataclasses import dataclass
from typing import TYPE_CHECKING, TypeVar, Generic
import ba import ba
@ -12,6 +13,70 @@ if TYPE_CHECKING:
from typing import Any, Callable, Dict, Tuple, List, Sequence, Optional from typing import Any, Callable, Dict, Tuple, List, Sequence, Optional
@dataclass
class Tab:
"""Info for an individual tab in a TabRow"""
button: ba.Widget
position: Tuple[float, float]
size: Tuple[float, float]
T = TypeVar('T')
class TabRow(Generic[T]):
"""Encapsulates a row of tab-styled buttons.
Tabs are indexed by id which is an arbitrary user-provided type.
"""
def __init__(self,
parent: ba.Widget,
tabdefs: List[Tuple[T, ba.Lstr]],
pos: Tuple[float, float],
size: Tuple[float, float],
on_select_call: Callable[[T], None] = None) -> None:
if not tabdefs:
raise ValueError('At least one tab def is required')
self.tabs: Dict[T, Tab] = {}
tab_pos_v = pos[1]
tab_button_width = float(size[0]) / len(tabdefs)
tab_spacing = (250.0 - tab_button_width) * 0.06
h = pos[0]
for tab_id, tab_label in tabdefs:
pos = (h + tab_spacing * 0.5, tab_pos_v)
size = (tab_button_width - tab_spacing, 50.0)
btn = ba.buttonwidget(parent=parent,
position=pos,
autoselect=True,
button_type='tab',
size=size,
label=tab_label,
enable_sound=False,
on_activate_call=ba.Call(
self._tick_and_call, on_select_call,
tab_id))
h += tab_button_width
self.tabs[tab_id] = Tab(button=btn, position=pos, size=size)
def update_appearance(self, selected_tab_id: T) -> None:
"""Update appearances to make the provided tab appear selected."""
for tab_id, tab in self.tabs.items():
if tab_id == selected_tab_id:
ba.buttonwidget(edit=tab.button,
color=(0.5, 0.4, 0.93),
textcolor=(0.85, 0.75, 0.95)) # lit
else:
ba.buttonwidget(edit=tab.button,
color=(0.52, 0.48, 0.63),
textcolor=(0.65, 0.6, 0.7)) # unlit
def _tick_and_call(self, call: Optional[Callable], arg: Any) -> None:
ba.playsound(ba.getsound('click01'))
if call is not None:
call(arg)
def create_tab_buttons(parent_widget: ba.Widget, def create_tab_buttons(parent_widget: ba.Widget,
tabs: List[Tuple[str, ba.Lstr]], tabs: List[Tuple[str, ba.Lstr]],
pos: Sequence[float], pos: Sequence[float],
@ -25,7 +90,7 @@ def create_tab_buttons(parent_widget: ba.Widget,
tab_buttons_indexed = [] tab_buttons_indexed = []
tab_button_width = float(size[0]) / len(tabs) tab_button_width = float(size[0]) / len(tabs)
# add a bit more visual spacing as our buttons get narrower # Add a bit more visual spacing as our buttons get narrower.
tab_spacing = (250.0 - tab_button_width) * 0.06 tab_spacing = (250.0 - tab_button_width) * 0.06
positions = [] positions = []
sizes = [] sizes = []

View File

@ -5,6 +5,7 @@
from __future__ import annotations from __future__ import annotations
import os import os
from enum import Enum
from typing import TYPE_CHECKING, cast from typing import TYPE_CHECKING, cast
import _ba import _ba
@ -14,6 +15,12 @@ if TYPE_CHECKING:
from typing import Any, Optional, Tuple, Dict from typing import Any, Optional, Tuple, Dict
class TabID(Enum):
"""Our available tab types."""
MY_REPLAYS = 'my_replays'
TEST_TAB = 'test_tab'
class WatchWindow(ba.Window): class WatchWindow(ba.Window):
"""Window for watching replays.""" """Window for watching replays."""
@ -22,7 +29,7 @@ class WatchWindow(ba.Window):
origin_widget: ba.Widget = None): origin_widget: ba.Widget = None):
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
from bastd.ui import tabs from bastd.ui.tabs import TabRow
ba.set_analytics_screen('Watch Window') ba.set_analytics_screen('Watch Window')
scale_origin: Optional[Tuple[float, float]] scale_origin: Optional[Tuple[float, float]]
if origin_widget is not None: if origin_widget is not None:
@ -47,7 +54,7 @@ class WatchWindow(ba.Window):
x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0
self._height = (578 if uiscale is ba.UIScale.SMALL else self._height = (578 if uiscale is ba.UIScale.SMALL else
670 if uiscale is ba.UIScale.MEDIUM else 800) 670 if uiscale is ba.UIScale.MEDIUM else 800)
self._current_tab: Optional[str] = None self._current_tab: Optional[TabID] = None
extra_top = 20 if uiscale is ba.UIScale.SMALL else 0 extra_top = 20 if uiscale is ba.UIScale.SMALL else 0
super().__init__(root_widget=ba.containerwidget( super().__init__(root_widget=ba.containerwidget(
@ -90,32 +97,35 @@ class WatchWindow(ba.Window):
text=ba.Lstr(resource=self._r + '.titleText'), text=ba.Lstr(resource=self._r + '.titleText'),
maxwidth=400) maxwidth=400)
tabs_def = [('my_replays', tabdefs = [
ba.Lstr(resource=self._r + '.myReplaysText'))] (TabID.MY_REPLAYS, ba.Lstr(resource=self._r + '.myReplaysText')),
# (TabID.TEST_TAB, ba.Lstr(value='Testing')),
]
scroll_buffer_h = 130 + 2 * x_inset scroll_buffer_h = 130 + 2 * x_inset
tab_buffer_h = 750 + 2 * x_inset tab_buffer_h = 750 + 2 * x_inset
self._tab_buttons = tabs.create_tab_buttons( self._tab_row = TabRow(self._root_widget,
self._root_widget, tabdefs,
tabs_def, pos=(tab_buffer_h * 0.5, self._height - 130),
pos=(tab_buffer_h * 0.5, self._height - 130), size=(self._width - tab_buffer_h, 50),
size=(self._width - tab_buffer_h, 50), on_select_call=self._set_tab)
on_select_call=self._set_tab)
if ba.app.ui.use_toolbars: if ba.app.ui.use_toolbars:
ba.widget(edit=self._tab_buttons[tabs_def[-1][0]], first_tab = self._tab_row.tabs[tabdefs[0][0]]
last_tab = self._tab_row.tabs[tabdefs[-1][0]]
ba.widget(edit=last_tab.button,
right_widget=_ba.get_special_widget('party_button')) right_widget=_ba.get_special_widget('party_button'))
if uiscale is ba.UIScale.SMALL: if uiscale is ba.UIScale.SMALL:
bbtn = _ba.get_special_widget('back_button') bbtn = _ba.get_special_widget('back_button')
ba.widget(edit=self._tab_buttons[tabs_def[0][0]], ba.widget(edit=first_tab.button,
up_widget=bbtn, up_widget=bbtn,
left_widget=bbtn) left_widget=bbtn)
self._scroll_width = self._width - scroll_buffer_h self._scroll_width = self._width - scroll_buffer_h
self._scroll_height = self._height - 180 self._scroll_height = self._height - 180
# not actually using a scroll widget anymore; just an image # Not actually using a scroll widget anymore; just an image.
scroll_left = (self._width - self._scroll_width) * 0.5 scroll_left = (self._width - self._scroll_width) * 0.5
scroll_bottom = self._height - self._scroll_height - 79 - 48 scroll_bottom = self._height - self._scroll_height - 79 - 48
buffer_h = 10 buffer_h = 10
@ -131,21 +141,21 @@ class WatchWindow(ba.Window):
self._restore_state() self._restore_state()
def _set_tab(self, tab: str) -> None: def _set_tab(self, tab_id: TabID) -> None:
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
from bastd.ui import tabs
if self._current_tab == tab: if self._current_tab == tab_id:
return return
self._current_tab = tab self._current_tab = tab_id
# We wanna preserve our current tab between runs. # Preserve our current tab between runs.
cfg = ba.app.config cfg = ba.app.config
cfg['Watch Tab'] = tab cfg['Watch Tab'] = tab_id.value
cfg.commit() cfg.commit()
# Update tab colors based on which is selected. # Update tab colors based on which is selected.
tabs.update_tab_button_colors(self._tab_buttons, tab) # tabs.update_tab_button_colors(self._tab_buttons, tab)
self._tab_row.update_appearance(tab_id)
if self._tab_container: if self._tab_container:
self._tab_container.delete() self._tab_container.delete()
@ -157,7 +167,7 @@ class WatchWindow(ba.Window):
self._tab_data = {} self._tab_data = {}
uiscale = ba.app.ui.uiscale uiscale = ba.app.ui.uiscale
if tab == 'my_replays': if tab_id is TabID.MY_REPLAYS:
c_width = self._scroll_width c_width = self._scroll_width
c_height = self._scroll_height - 20 c_height = self._scroll_height - 20
sub_scroll_height = c_height - 63 sub_scroll_height = c_height - 63
@ -212,7 +222,7 @@ class WatchWindow(ba.Window):
text_scale=tscl, text_scale=tscl,
label=ba.Lstr(resource=self._r + '.watchReplayButtonText'), label=ba.Lstr(resource=self._r + '.watchReplayButtonText'),
autoselect=True) autoselect=True)
ba.widget(edit=btn1, up_widget=self._tab_buttons[tab]) ba.widget(edit=btn1, up_widget=self._tab_row.tabs[tab_id].button)
if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars:
ba.widget(edit=btn1, ba.widget(edit=btn1,
left_widget=_ba.get_special_widget('back_button')) left_widget=_ba.get_special_widget('back_button'))
@ -255,8 +265,9 @@ class WatchWindow(ba.Window):
ba.widget(edit=scrlw, ba.widget(edit=scrlw,
autoselect=True, autoselect=True,
left_widget=btn1, left_widget=btn1,
up_widget=self._tab_buttons[tab]) up_widget=self._tab_row.tabs[tab_id].button)
ba.widget(edit=self._tab_buttons[tab], down_widget=scrlw) ba.widget(edit=self._tab_row.tabs[tab_id].button,
down_widget=scrlw)
self._my_replay_selected = None self._my_replay_selected = None
self._refresh_my_replays() self._refresh_my_replays()
@ -463,23 +474,28 @@ class WatchWindow(ba.Window):
corner_scale=t_scale, corner_scale=t_scale,
maxwidth=(self._my_replays_scroll_width / t_scale) * 0.93) maxwidth=(self._my_replays_scroll_width / t_scale) * 0.93)
if i == 0: if i == 0:
ba.widget(edit=txt, up_widget=self._tab_buttons['my_replays']) ba.widget(
edit=txt,
up_widget=self._tab_row.tabs[TabID.MY_REPLAYS].button)
def _save_state(self) -> None: def _save_state(self) -> None:
try: try:
sel = self._root_widget.get_selected_child() sel = self._root_widget.get_selected_child()
selected_tab_ids = [
tab_id for tab_id, tab in self._tab_row.tabs.items()
if sel == tab.button
]
if sel == self._back_button: if sel == self._back_button:
sel_name = 'Back' sel_name = 'Back'
elif sel in list(self._tab_buttons.values()): elif selected_tab_ids:
sel_name = 'Tab:' + list(self._tab_buttons.keys())[list( assert len(selected_tab_ids) == 1
self._tab_buttons.values()).index(sel)] sel_name = f'Tab:{selected_tab_ids[0].value}'
elif sel == self._tab_container: elif sel == self._tab_container:
sel_name = 'TabContainer' sel_name = 'TabContainer'
else: else:
raise ValueError(f'unrecognized selection {sel}') raise ValueError(f'unrecognized selection {sel}')
ba.app.ui.window_states[self.__class__.__name__] = { ba.app.ui.window_states[self.__class__.__name__] = {
'sel_name': sel_name, 'sel_name': sel_name
'tab': self._current_tab
} }
except Exception: except Exception:
ba.print_exception(f'Error saving state for {self}.') ba.print_exception(f'Error saving state for {self}.')
@ -488,21 +504,28 @@ class WatchWindow(ba.Window):
try: try:
sel_name = ba.app.ui.window_states.get(self.__class__.__name__, sel_name = ba.app.ui.window_states.get(self.__class__.__name__,
{}).get('sel_name') {}).get('sel_name')
current_tab = ba.app.config.get('Watch Tab') assert isinstance(sel_name, (str, type(None)))
if current_tab is None or current_tab not in self._tab_buttons: try:
current_tab = 'my_replays' current_tab = TabID(ba.app.config.get('Watch Tab'))
except ValueError:
current_tab = TabID.MY_REPLAYS
self._set_tab(current_tab) self._set_tab(current_tab)
if sel_name == 'Back': if sel_name == 'Back':
sel = self._back_button sel = self._back_button
elif sel_name == 'TabContainer': elif sel_name == 'TabContainer':
sel = self._tab_container sel = self._tab_container
elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
sel = self._tab_buttons[sel_name.split(':')[-1]] try:
sel_tab_id = TabID(sel_name.split(':')[-1])
except ValueError:
sel_tab_id = TabID.MY_REPLAYS
sel = self._tab_row.tabs[sel_tab_id].button
else: else:
if self._tab_container is not None: if self._tab_container is not None:
sel = self._tab_container sel = self._tab_container
else: else:
sel = self._tab_buttons[current_tab] sel = self._tab_row.tabs[current_tab].button
ba.containerwidget(edit=self._root_widget, selected_child=sel) ba.containerwidget(edit=self._root_widget, selected_child=sel)
except Exception: except Exception:
ba.print_exception(f'Error restoring state for {self}.') ba.print_exception(f'Error restoring state for {self}.')

View File

@ -814,6 +814,7 @@
<w>sval</w> <w>sval</w>
<w>symbolification</w> <w>symbolification</w>
<w>syscalls</w> <w>syscalls</w>
<w>tabdefs</w>
<w>talloc</w> <w>talloc</w>
<w>tegra</w> <w>tegra</w>
<w>telefonaktiebolaget</w> <w>telefonaktiebolaget</w>

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND --> <!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-10-17 for Ballistica version 1.5.27 build 20223</em></h4> <h4><em>last updated on 2020-10-19 for Ballistica version 1.5.27 build 20224</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module, <p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p> which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr> <hr>

View File

@ -5,23 +5,15 @@
#include <map> #include <map>
#include "ballistica/app/app.h" #include "ballistica/app/app.h"
#include "ballistica/app/app_config.h"
#include "ballistica/app/app_globals.h"
#include "ballistica/audio/audio.h"
#include "ballistica/audio/audio_server.h" #include "ballistica/audio/audio_server.h"
#include "ballistica/core/fatal_error.h" #include "ballistica/core/fatal_error.h"
#include "ballistica/core/logging.h" #include "ballistica/core/logging.h"
#include "ballistica/core/thread.h" #include "ballistica/core/thread.h"
#include "ballistica/dynamics/bg/bg_dynamics.h"
#include "ballistica/dynamics/bg/bg_dynamics_server.h" #include "ballistica/dynamics/bg/bg_dynamics_server.h"
#include "ballistica/game/account.h" #include "ballistica/game/account.h"
#include "ballistica/graphics/graphics.h"
#include "ballistica/graphics/graphics_server.h" #include "ballistica/graphics/graphics_server.h"
#include "ballistica/input/input.h"
#include "ballistica/media/media.h"
#include "ballistica/media/media_server.h" #include "ballistica/media/media_server.h"
#include "ballistica/networking/network_write_module.h" #include "ballistica/networking/network_write_module.h"
#include "ballistica/networking/networking.h"
#include "ballistica/platform/platform.h" #include "ballistica/platform/platform.h"
#include "ballistica/python/python.h" #include "ballistica/python/python.h"
#include "ballistica/scene/scene.h" #include "ballistica/scene/scene.h"
@ -29,7 +21,7 @@
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't change here. // These are set automatically via script; don't change here.
const int kAppBuildNumber = 20223; const int kAppBuildNumber = 20224;
const char* kAppVersion = "1.5.27"; const char* kAppVersion = "1.5.27";
// Our standalone globals. // Our standalone globals.