bauiv1lib.gather
Provides UI for inviting/joining friends.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides UI for inviting/joining friends.""" 4 5from __future__ import annotations 6 7import weakref 8import logging 9from enum import Enum 10 11from bauiv1lib.tabs import TabRow 12import bauiv1 as bui 13 14 15class GatherTab: 16 """Defines a tab for use in the gather UI.""" 17 18 def __init__(self, window: GatherWindow) -> None: 19 self._window = weakref.ref(window) 20 21 @property 22 def window(self) -> GatherWindow: 23 """The GatherWindow that this tab belongs to.""" 24 window = self._window() 25 if window is None: 26 raise bui.NotFoundError("GatherTab's window no longer exists.") 27 return window 28 29 def on_activate( 30 self, 31 parent_widget: bui.Widget, 32 tab_button: bui.Widget, 33 region_width: float, 34 region_height: float, 35 region_left: float, 36 region_bottom: float, 37 ) -> bui.Widget: 38 """Called when the tab becomes the active one. 39 40 The tab should create and return a container widget covering the 41 specified region. 42 """ 43 raise RuntimeError('Should not get here.') 44 45 def on_deactivate(self) -> None: 46 """Called when the tab will no longer be the active one.""" 47 48 def save_state(self) -> None: 49 """Called when the parent window is saving state.""" 50 51 def restore_state(self) -> None: 52 """Called when the parent window is restoring state.""" 53 54 55class GatherWindow(bui.Window): 56 """Window for joining/inviting friends.""" 57 58 class TabID(Enum): 59 """Our available tab types.""" 60 61 ABOUT = 'about' 62 INTERNET = 'internet' 63 PRIVATE = 'private' 64 NEARBY = 'nearby' 65 MANUAL = 'manual' 66 67 def __init__( 68 self, 69 transition: str | None = 'in_right', 70 origin_widget: bui.Widget | None = None, 71 ): 72 # pylint: disable=too-many-statements 73 # pylint: disable=too-many-locals 74 # pylint: disable=cyclic-import 75 from bauiv1lib.gather.abouttab import AboutGatherTab 76 from bauiv1lib.gather.manualtab import ManualGatherTab 77 from bauiv1lib.gather.privatetab import PrivateGatherTab 78 from bauiv1lib.gather.publictab import PublicGatherTab 79 from bauiv1lib.gather.nearbytab import NearbyGatherTab 80 81 plus = bui.app.plus 82 assert plus is not None 83 84 bui.set_analytics_screen('Gather Window') 85 scale_origin: tuple[float, float] | None 86 if origin_widget is not None: 87 self._transition_out = 'out_scale' 88 scale_origin = origin_widget.get_screen_space_center() 89 transition = 'in_scale' 90 else: 91 self._transition_out = 'out_right' 92 scale_origin = None 93 assert bui.app.classic is not None 94 bui.app.ui_v1.set_main_menu_location('Gather') 95 bui.set_party_icon_always_visible(True) 96 uiscale = bui.app.ui_v1.uiscale 97 self._width = 1240 if uiscale is bui.UIScale.SMALL else 1040 98 x_offs = 100 if uiscale is bui.UIScale.SMALL else 0 99 self._height = ( 100 582 101 if uiscale is bui.UIScale.SMALL 102 else 680 103 if uiscale is bui.UIScale.MEDIUM 104 else 800 105 ) 106 self._current_tab: GatherWindow.TabID | None = None 107 extra_top = 20 if uiscale is bui.UIScale.SMALL else 0 108 self._r = 'gatherWindow' 109 110 super().__init__( 111 root_widget=bui.containerwidget( 112 size=(self._width, self._height + extra_top), 113 transition=transition, 114 toolbar_visibility='menu_minimal', 115 scale_origin_stack_offset=scale_origin, 116 scale=( 117 1.3 118 if uiscale is bui.UIScale.SMALL 119 else 0.97 120 if uiscale is bui.UIScale.MEDIUM 121 else 0.8 122 ), 123 stack_offset=(0, -11) 124 if uiscale is bui.UIScale.SMALL 125 else (0, 0) 126 if uiscale is bui.UIScale.MEDIUM 127 else (0, 0), 128 ) 129 ) 130 131 if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars: 132 bui.containerwidget( 133 edit=self._root_widget, on_cancel_call=self._back 134 ) 135 self._back_button = None 136 else: 137 self._back_button = btn = bui.buttonwidget( 138 parent=self._root_widget, 139 position=(70 + x_offs, self._height - 74), 140 size=(140, 60), 141 scale=1.1, 142 autoselect=True, 143 label=bui.Lstr(resource='backText'), 144 button_type='back', 145 on_activate_call=self._back, 146 ) 147 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 148 bui.buttonwidget( 149 edit=btn, 150 button_type='backSmall', 151 position=(70 + x_offs, self._height - 78), 152 size=(60, 60), 153 label=bui.charstr(bui.SpecialChar.BACK), 154 ) 155 156 condensed = uiscale is not bui.UIScale.LARGE 157 t_offs_y = ( 158 0 if not condensed else 25 if uiscale is bui.UIScale.MEDIUM else 17 159 ) 160 bui.textwidget( 161 parent=self._root_widget, 162 position=(self._width * 0.5, self._height - 42 + t_offs_y), 163 size=(0, 0), 164 color=bui.app.ui_v1.title_color, 165 scale=( 166 1.5 167 if not condensed 168 else 1.0 169 if uiscale is bui.UIScale.MEDIUM 170 else 0.6 171 ), 172 h_align='center', 173 v_align='center', 174 text=bui.Lstr(resource=self._r + '.titleText'), 175 maxwidth=550, 176 ) 177 178 scroll_buffer_h = 130 + 2 * x_offs 179 tab_buffer_h = (320 if condensed else 250) + 2 * x_offs 180 181 # Build up the set of tabs we want. 182 tabdefs: list[tuple[GatherWindow.TabID, bui.Lstr]] = [ 183 (self.TabID.ABOUT, bui.Lstr(resource=self._r + '.aboutText')) 184 ] 185 if plus.get_v1_account_misc_read_val('enablePublicParties', True): 186 tabdefs.append( 187 ( 188 self.TabID.INTERNET, 189 bui.Lstr(resource=self._r + '.publicText'), 190 ) 191 ) 192 tabdefs.append( 193 (self.TabID.PRIVATE, bui.Lstr(resource=self._r + '.privateText')) 194 ) 195 tabdefs.append( 196 (self.TabID.NEARBY, bui.Lstr(resource=self._r + '.nearbyText')) 197 ) 198 tabdefs.append( 199 (self.TabID.MANUAL, bui.Lstr(resource=self._r + '.manualText')) 200 ) 201 202 # On small UI, push our tabs up closer to the top of the screen to 203 # save a bit of space. 204 tabs_top_extra = 42 if condensed else 0 205 self._tab_row = TabRow( 206 self._root_widget, 207 tabdefs, 208 pos=(tab_buffer_h * 0.5, self._height - 130 + tabs_top_extra), 209 size=(self._width - tab_buffer_h, 50), 210 on_select_call=bui.WeakCall(self._set_tab), 211 ) 212 213 # Now instantiate handlers for these tabs. 214 tabtypes: dict[GatherWindow.TabID, type[GatherTab]] = { 215 self.TabID.ABOUT: AboutGatherTab, 216 self.TabID.MANUAL: ManualGatherTab, 217 self.TabID.PRIVATE: PrivateGatherTab, 218 self.TabID.INTERNET: PublicGatherTab, 219 self.TabID.NEARBY: NearbyGatherTab, 220 } 221 self._tabs: dict[GatherWindow.TabID, GatherTab] = {} 222 for tab_id in self._tab_row.tabs: 223 tabtype = tabtypes.get(tab_id) 224 if tabtype is not None: 225 self._tabs[tab_id] = tabtype(self) 226 227 if bui.app.ui_v1.use_toolbars: 228 bui.widget( 229 edit=self._tab_row.tabs[tabdefs[-1][0]].button, 230 right_widget=bui.get_special_widget('party_button'), 231 ) 232 if uiscale is bui.UIScale.SMALL: 233 bui.widget( 234 edit=self._tab_row.tabs[tabdefs[0][0]].button, 235 left_widget=bui.get_special_widget('back_button'), 236 ) 237 238 self._scroll_width = self._width - scroll_buffer_h 239 self._scroll_height = self._height - 180.0 + tabs_top_extra 240 241 self._scroll_left = (self._width - self._scroll_width) * 0.5 242 self._scroll_bottom = ( 243 self._height - self._scroll_height - 79 - 48 + tabs_top_extra 244 ) 245 buffer_h = 10 246 buffer_v = 4 247 248 # Not actually using a scroll widget anymore; just an image. 249 bui.imagewidget( 250 parent=self._root_widget, 251 position=( 252 self._scroll_left - buffer_h, 253 self._scroll_bottom - buffer_v, 254 ), 255 size=( 256 self._scroll_width + 2 * buffer_h, 257 self._scroll_height + 2 * buffer_v, 258 ), 259 texture=bui.gettexture('scrollWidget'), 260 mesh_transparent=bui.getmesh('softEdgeOutside'), 261 ) 262 self._tab_container: bui.Widget | None = None 263 264 self._restore_state() 265 266 def __del__(self) -> None: 267 bui.set_party_icon_always_visible(False) 268 269 def playlist_select(self, origin_widget: bui.Widget) -> None: 270 """Called by the private-hosting tab to select a playlist.""" 271 from bauiv1lib.play import PlayWindow 272 273 self._save_state() 274 bui.containerwidget(edit=self._root_widget, transition='out_left') 275 assert bui.app.classic is not None 276 bui.app.ui_v1.selecting_private_party_playlist = True 277 bui.app.ui_v1.set_main_menu_window( 278 PlayWindow(origin_widget=origin_widget).get_root_widget() 279 ) 280 281 def _set_tab(self, tab_id: TabID) -> None: 282 if self._current_tab is tab_id: 283 return 284 prev_tab_id = self._current_tab 285 self._current_tab = tab_id 286 287 # We wanna preserve our current tab between runs. 288 cfg = bui.app.config 289 cfg['Gather Tab'] = tab_id.value 290 cfg.commit() 291 292 # Update tab colors based on which is selected. 293 self._tab_row.update_appearance(tab_id) 294 295 if prev_tab_id is not None: 296 prev_tab = self._tabs.get(prev_tab_id) 297 if prev_tab is not None: 298 prev_tab.on_deactivate() 299 300 # Clear up prev container if it hasn't been done. 301 if self._tab_container: 302 self._tab_container.delete() 303 304 tab = self._tabs.get(tab_id) 305 if tab is not None: 306 self._tab_container = tab.on_activate( 307 self._root_widget, 308 self._tab_row.tabs[tab_id].button, 309 self._scroll_width, 310 self._scroll_height, 311 self._scroll_left, 312 self._scroll_bottom, 313 ) 314 return 315 316 def _save_state(self) -> None: 317 try: 318 for tab in self._tabs.values(): 319 tab.save_state() 320 321 sel = self._root_widget.get_selected_child() 322 selected_tab_ids = [ 323 tab_id 324 for tab_id, tab in self._tab_row.tabs.items() 325 if sel == tab.button 326 ] 327 if sel == self._back_button: 328 sel_name = 'Back' 329 elif selected_tab_ids: 330 assert len(selected_tab_ids) == 1 331 sel_name = f'Tab:{selected_tab_ids[0].value}' 332 elif sel == self._tab_container: 333 sel_name = 'TabContainer' 334 else: 335 raise ValueError(f'unrecognized selection: \'{sel}\'') 336 assert bui.app.classic is not None 337 bui.app.ui_v1.window_states[type(self)] = { 338 'sel_name': sel_name, 339 } 340 except Exception: 341 logging.exception('Error saving state for %s.', self) 342 343 def _restore_state(self) -> None: 344 from efro.util import enum_by_value 345 346 try: 347 for tab in self._tabs.values(): 348 tab.restore_state() 349 350 sel: bui.Widget | None 351 assert bui.app.classic is not None 352 winstate = bui.app.ui_v1.window_states.get(type(self), {}) 353 sel_name = winstate.get('sel_name', None) 354 assert isinstance(sel_name, (str, type(None))) 355 current_tab = self.TabID.ABOUT 356 gather_tab_val = bui.app.config.get('Gather Tab') 357 try: 358 stored_tab = enum_by_value(self.TabID, gather_tab_val) 359 if stored_tab in self._tab_row.tabs: 360 current_tab = stored_tab 361 except ValueError: 362 pass 363 self._set_tab(current_tab) 364 if sel_name == 'Back': 365 sel = self._back_button 366 elif sel_name == 'TabContainer': 367 sel = self._tab_container 368 elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): 369 try: 370 sel_tab_id = enum_by_value( 371 self.TabID, sel_name.split(':')[-1] 372 ) 373 except ValueError: 374 sel_tab_id = self.TabID.ABOUT 375 sel = self._tab_row.tabs[sel_tab_id].button 376 else: 377 sel = self._tab_row.tabs[current_tab].button 378 bui.containerwidget(edit=self._root_widget, selected_child=sel) 379 380 except Exception: 381 logging.exception('Error restoring state for %s.', self) 382 383 def _back(self) -> None: 384 from bauiv1lib.mainmenu import MainMenuWindow 385 386 self._save_state() 387 bui.containerwidget( 388 edit=self._root_widget, transition=self._transition_out 389 ) 390 assert bui.app.classic is not None 391 bui.app.ui_v1.set_main_menu_window( 392 MainMenuWindow(transition='in_left').get_root_widget() 393 )
class
GatherTab:
16class GatherTab: 17 """Defines a tab for use in the gather UI.""" 18 19 def __init__(self, window: GatherWindow) -> None: 20 self._window = weakref.ref(window) 21 22 @property 23 def window(self) -> GatherWindow: 24 """The GatherWindow that this tab belongs to.""" 25 window = self._window() 26 if window is None: 27 raise bui.NotFoundError("GatherTab's window no longer exists.") 28 return window 29 30 def on_activate( 31 self, 32 parent_widget: bui.Widget, 33 tab_button: bui.Widget, 34 region_width: float, 35 region_height: float, 36 region_left: float, 37 region_bottom: float, 38 ) -> bui.Widget: 39 """Called when the tab becomes the active one. 40 41 The tab should create and return a container widget covering the 42 specified region. 43 """ 44 raise RuntimeError('Should not get here.') 45 46 def on_deactivate(self) -> None: 47 """Called when the tab will no longer be the active one.""" 48 49 def save_state(self) -> None: 50 """Called when the parent window is saving state.""" 51 52 def restore_state(self) -> None: 53 """Called when the parent window is restoring state."""
Defines a tab for use in the gather UI.
GatherTab(window: GatherWindow)
def
on_activate( self, parent_widget: _bauiv1.Widget, tab_button: _bauiv1.Widget, region_width: float, region_height: float, region_left: float, region_bottom: float) -> _bauiv1.Widget:
30 def on_activate( 31 self, 32 parent_widget: bui.Widget, 33 tab_button: bui.Widget, 34 region_width: float, 35 region_height: float, 36 region_left: float, 37 region_bottom: float, 38 ) -> bui.Widget: 39 """Called when the tab becomes the active one. 40 41 The tab should create and return a container widget covering the 42 specified region. 43 """ 44 raise RuntimeError('Should not get here.')
Called when the tab becomes the active one.
The tab should create and return a container widget covering the specified region.
class
GatherWindow(bauiv1._uitypes.Window):
56class GatherWindow(bui.Window): 57 """Window for joining/inviting friends.""" 58 59 class TabID(Enum): 60 """Our available tab types.""" 61 62 ABOUT = 'about' 63 INTERNET = 'internet' 64 PRIVATE = 'private' 65 NEARBY = 'nearby' 66 MANUAL = 'manual' 67 68 def __init__( 69 self, 70 transition: str | None = 'in_right', 71 origin_widget: bui.Widget | None = None, 72 ): 73 # pylint: disable=too-many-statements 74 # pylint: disable=too-many-locals 75 # pylint: disable=cyclic-import 76 from bauiv1lib.gather.abouttab import AboutGatherTab 77 from bauiv1lib.gather.manualtab import ManualGatherTab 78 from bauiv1lib.gather.privatetab import PrivateGatherTab 79 from bauiv1lib.gather.publictab import PublicGatherTab 80 from bauiv1lib.gather.nearbytab import NearbyGatherTab 81 82 plus = bui.app.plus 83 assert plus is not None 84 85 bui.set_analytics_screen('Gather Window') 86 scale_origin: tuple[float, float] | None 87 if origin_widget is not None: 88 self._transition_out = 'out_scale' 89 scale_origin = origin_widget.get_screen_space_center() 90 transition = 'in_scale' 91 else: 92 self._transition_out = 'out_right' 93 scale_origin = None 94 assert bui.app.classic is not None 95 bui.app.ui_v1.set_main_menu_location('Gather') 96 bui.set_party_icon_always_visible(True) 97 uiscale = bui.app.ui_v1.uiscale 98 self._width = 1240 if uiscale is bui.UIScale.SMALL else 1040 99 x_offs = 100 if uiscale is bui.UIScale.SMALL else 0 100 self._height = ( 101 582 102 if uiscale is bui.UIScale.SMALL 103 else 680 104 if uiscale is bui.UIScale.MEDIUM 105 else 800 106 ) 107 self._current_tab: GatherWindow.TabID | None = None 108 extra_top = 20 if uiscale is bui.UIScale.SMALL else 0 109 self._r = 'gatherWindow' 110 111 super().__init__( 112 root_widget=bui.containerwidget( 113 size=(self._width, self._height + extra_top), 114 transition=transition, 115 toolbar_visibility='menu_minimal', 116 scale_origin_stack_offset=scale_origin, 117 scale=( 118 1.3 119 if uiscale is bui.UIScale.SMALL 120 else 0.97 121 if uiscale is bui.UIScale.MEDIUM 122 else 0.8 123 ), 124 stack_offset=(0, -11) 125 if uiscale is bui.UIScale.SMALL 126 else (0, 0) 127 if uiscale is bui.UIScale.MEDIUM 128 else (0, 0), 129 ) 130 ) 131 132 if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars: 133 bui.containerwidget( 134 edit=self._root_widget, on_cancel_call=self._back 135 ) 136 self._back_button = None 137 else: 138 self._back_button = btn = bui.buttonwidget( 139 parent=self._root_widget, 140 position=(70 + x_offs, self._height - 74), 141 size=(140, 60), 142 scale=1.1, 143 autoselect=True, 144 label=bui.Lstr(resource='backText'), 145 button_type='back', 146 on_activate_call=self._back, 147 ) 148 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 149 bui.buttonwidget( 150 edit=btn, 151 button_type='backSmall', 152 position=(70 + x_offs, self._height - 78), 153 size=(60, 60), 154 label=bui.charstr(bui.SpecialChar.BACK), 155 ) 156 157 condensed = uiscale is not bui.UIScale.LARGE 158 t_offs_y = ( 159 0 if not condensed else 25 if uiscale is bui.UIScale.MEDIUM else 17 160 ) 161 bui.textwidget( 162 parent=self._root_widget, 163 position=(self._width * 0.5, self._height - 42 + t_offs_y), 164 size=(0, 0), 165 color=bui.app.ui_v1.title_color, 166 scale=( 167 1.5 168 if not condensed 169 else 1.0 170 if uiscale is bui.UIScale.MEDIUM 171 else 0.6 172 ), 173 h_align='center', 174 v_align='center', 175 text=bui.Lstr(resource=self._r + '.titleText'), 176 maxwidth=550, 177 ) 178 179 scroll_buffer_h = 130 + 2 * x_offs 180 tab_buffer_h = (320 if condensed else 250) + 2 * x_offs 181 182 # Build up the set of tabs we want. 183 tabdefs: list[tuple[GatherWindow.TabID, bui.Lstr]] = [ 184 (self.TabID.ABOUT, bui.Lstr(resource=self._r + '.aboutText')) 185 ] 186 if plus.get_v1_account_misc_read_val('enablePublicParties', True): 187 tabdefs.append( 188 ( 189 self.TabID.INTERNET, 190 bui.Lstr(resource=self._r + '.publicText'), 191 ) 192 ) 193 tabdefs.append( 194 (self.TabID.PRIVATE, bui.Lstr(resource=self._r + '.privateText')) 195 ) 196 tabdefs.append( 197 (self.TabID.NEARBY, bui.Lstr(resource=self._r + '.nearbyText')) 198 ) 199 tabdefs.append( 200 (self.TabID.MANUAL, bui.Lstr(resource=self._r + '.manualText')) 201 ) 202 203 # On small UI, push our tabs up closer to the top of the screen to 204 # save a bit of space. 205 tabs_top_extra = 42 if condensed else 0 206 self._tab_row = TabRow( 207 self._root_widget, 208 tabdefs, 209 pos=(tab_buffer_h * 0.5, self._height - 130 + tabs_top_extra), 210 size=(self._width - tab_buffer_h, 50), 211 on_select_call=bui.WeakCall(self._set_tab), 212 ) 213 214 # Now instantiate handlers for these tabs. 215 tabtypes: dict[GatherWindow.TabID, type[GatherTab]] = { 216 self.TabID.ABOUT: AboutGatherTab, 217 self.TabID.MANUAL: ManualGatherTab, 218 self.TabID.PRIVATE: PrivateGatherTab, 219 self.TabID.INTERNET: PublicGatherTab, 220 self.TabID.NEARBY: NearbyGatherTab, 221 } 222 self._tabs: dict[GatherWindow.TabID, GatherTab] = {} 223 for tab_id in self._tab_row.tabs: 224 tabtype = tabtypes.get(tab_id) 225 if tabtype is not None: 226 self._tabs[tab_id] = tabtype(self) 227 228 if bui.app.ui_v1.use_toolbars: 229 bui.widget( 230 edit=self._tab_row.tabs[tabdefs[-1][0]].button, 231 right_widget=bui.get_special_widget('party_button'), 232 ) 233 if uiscale is bui.UIScale.SMALL: 234 bui.widget( 235 edit=self._tab_row.tabs[tabdefs[0][0]].button, 236 left_widget=bui.get_special_widget('back_button'), 237 ) 238 239 self._scroll_width = self._width - scroll_buffer_h 240 self._scroll_height = self._height - 180.0 + tabs_top_extra 241 242 self._scroll_left = (self._width - self._scroll_width) * 0.5 243 self._scroll_bottom = ( 244 self._height - self._scroll_height - 79 - 48 + tabs_top_extra 245 ) 246 buffer_h = 10 247 buffer_v = 4 248 249 # Not actually using a scroll widget anymore; just an image. 250 bui.imagewidget( 251 parent=self._root_widget, 252 position=( 253 self._scroll_left - buffer_h, 254 self._scroll_bottom - buffer_v, 255 ), 256 size=( 257 self._scroll_width + 2 * buffer_h, 258 self._scroll_height + 2 * buffer_v, 259 ), 260 texture=bui.gettexture('scrollWidget'), 261 mesh_transparent=bui.getmesh('softEdgeOutside'), 262 ) 263 self._tab_container: bui.Widget | None = None 264 265 self._restore_state() 266 267 def __del__(self) -> None: 268 bui.set_party_icon_always_visible(False) 269 270 def playlist_select(self, origin_widget: bui.Widget) -> None: 271 """Called by the private-hosting tab to select a playlist.""" 272 from bauiv1lib.play import PlayWindow 273 274 self._save_state() 275 bui.containerwidget(edit=self._root_widget, transition='out_left') 276 assert bui.app.classic is not None 277 bui.app.ui_v1.selecting_private_party_playlist = True 278 bui.app.ui_v1.set_main_menu_window( 279 PlayWindow(origin_widget=origin_widget).get_root_widget() 280 ) 281 282 def _set_tab(self, tab_id: TabID) -> None: 283 if self._current_tab is tab_id: 284 return 285 prev_tab_id = self._current_tab 286 self._current_tab = tab_id 287 288 # We wanna preserve our current tab between runs. 289 cfg = bui.app.config 290 cfg['Gather Tab'] = tab_id.value 291 cfg.commit() 292 293 # Update tab colors based on which is selected. 294 self._tab_row.update_appearance(tab_id) 295 296 if prev_tab_id is not None: 297 prev_tab = self._tabs.get(prev_tab_id) 298 if prev_tab is not None: 299 prev_tab.on_deactivate() 300 301 # Clear up prev container if it hasn't been done. 302 if self._tab_container: 303 self._tab_container.delete() 304 305 tab = self._tabs.get(tab_id) 306 if tab is not None: 307 self._tab_container = tab.on_activate( 308 self._root_widget, 309 self._tab_row.tabs[tab_id].button, 310 self._scroll_width, 311 self._scroll_height, 312 self._scroll_left, 313 self._scroll_bottom, 314 ) 315 return 316 317 def _save_state(self) -> None: 318 try: 319 for tab in self._tabs.values(): 320 tab.save_state() 321 322 sel = self._root_widget.get_selected_child() 323 selected_tab_ids = [ 324 tab_id 325 for tab_id, tab in self._tab_row.tabs.items() 326 if sel == tab.button 327 ] 328 if sel == self._back_button: 329 sel_name = 'Back' 330 elif selected_tab_ids: 331 assert len(selected_tab_ids) == 1 332 sel_name = f'Tab:{selected_tab_ids[0].value}' 333 elif sel == self._tab_container: 334 sel_name = 'TabContainer' 335 else: 336 raise ValueError(f'unrecognized selection: \'{sel}\'') 337 assert bui.app.classic is not None 338 bui.app.ui_v1.window_states[type(self)] = { 339 'sel_name': sel_name, 340 } 341 except Exception: 342 logging.exception('Error saving state for %s.', self) 343 344 def _restore_state(self) -> None: 345 from efro.util import enum_by_value 346 347 try: 348 for tab in self._tabs.values(): 349 tab.restore_state() 350 351 sel: bui.Widget | None 352 assert bui.app.classic is not None 353 winstate = bui.app.ui_v1.window_states.get(type(self), {}) 354 sel_name = winstate.get('sel_name', None) 355 assert isinstance(sel_name, (str, type(None))) 356 current_tab = self.TabID.ABOUT 357 gather_tab_val = bui.app.config.get('Gather Tab') 358 try: 359 stored_tab = enum_by_value(self.TabID, gather_tab_val) 360 if stored_tab in self._tab_row.tabs: 361 current_tab = stored_tab 362 except ValueError: 363 pass 364 self._set_tab(current_tab) 365 if sel_name == 'Back': 366 sel = self._back_button 367 elif sel_name == 'TabContainer': 368 sel = self._tab_container 369 elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): 370 try: 371 sel_tab_id = enum_by_value( 372 self.TabID, sel_name.split(':')[-1] 373 ) 374 except ValueError: 375 sel_tab_id = self.TabID.ABOUT 376 sel = self._tab_row.tabs[sel_tab_id].button 377 else: 378 sel = self._tab_row.tabs[current_tab].button 379 bui.containerwidget(edit=self._root_widget, selected_child=sel) 380 381 except Exception: 382 logging.exception('Error restoring state for %s.', self) 383 384 def _back(self) -> None: 385 from bauiv1lib.mainmenu import MainMenuWindow 386 387 self._save_state() 388 bui.containerwidget( 389 edit=self._root_widget, transition=self._transition_out 390 ) 391 assert bui.app.classic is not None 392 bui.app.ui_v1.set_main_menu_window( 393 MainMenuWindow(transition='in_left').get_root_widget() 394 )
Window for joining/inviting friends.
GatherWindow( transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
68 def __init__( 69 self, 70 transition: str | None = 'in_right', 71 origin_widget: bui.Widget | None = None, 72 ): 73 # pylint: disable=too-many-statements 74 # pylint: disable=too-many-locals 75 # pylint: disable=cyclic-import 76 from bauiv1lib.gather.abouttab import AboutGatherTab 77 from bauiv1lib.gather.manualtab import ManualGatherTab 78 from bauiv1lib.gather.privatetab import PrivateGatherTab 79 from bauiv1lib.gather.publictab import PublicGatherTab 80 from bauiv1lib.gather.nearbytab import NearbyGatherTab 81 82 plus = bui.app.plus 83 assert plus is not None 84 85 bui.set_analytics_screen('Gather Window') 86 scale_origin: tuple[float, float] | None 87 if origin_widget is not None: 88 self._transition_out = 'out_scale' 89 scale_origin = origin_widget.get_screen_space_center() 90 transition = 'in_scale' 91 else: 92 self._transition_out = 'out_right' 93 scale_origin = None 94 assert bui.app.classic is not None 95 bui.app.ui_v1.set_main_menu_location('Gather') 96 bui.set_party_icon_always_visible(True) 97 uiscale = bui.app.ui_v1.uiscale 98 self._width = 1240 if uiscale is bui.UIScale.SMALL else 1040 99 x_offs = 100 if uiscale is bui.UIScale.SMALL else 0 100 self._height = ( 101 582 102 if uiscale is bui.UIScale.SMALL 103 else 680 104 if uiscale is bui.UIScale.MEDIUM 105 else 800 106 ) 107 self._current_tab: GatherWindow.TabID | None = None 108 extra_top = 20 if uiscale is bui.UIScale.SMALL else 0 109 self._r = 'gatherWindow' 110 111 super().__init__( 112 root_widget=bui.containerwidget( 113 size=(self._width, self._height + extra_top), 114 transition=transition, 115 toolbar_visibility='menu_minimal', 116 scale_origin_stack_offset=scale_origin, 117 scale=( 118 1.3 119 if uiscale is bui.UIScale.SMALL 120 else 0.97 121 if uiscale is bui.UIScale.MEDIUM 122 else 0.8 123 ), 124 stack_offset=(0, -11) 125 if uiscale is bui.UIScale.SMALL 126 else (0, 0) 127 if uiscale is bui.UIScale.MEDIUM 128 else (0, 0), 129 ) 130 ) 131 132 if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars: 133 bui.containerwidget( 134 edit=self._root_widget, on_cancel_call=self._back 135 ) 136 self._back_button = None 137 else: 138 self._back_button = btn = bui.buttonwidget( 139 parent=self._root_widget, 140 position=(70 + x_offs, self._height - 74), 141 size=(140, 60), 142 scale=1.1, 143 autoselect=True, 144 label=bui.Lstr(resource='backText'), 145 button_type='back', 146 on_activate_call=self._back, 147 ) 148 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 149 bui.buttonwidget( 150 edit=btn, 151 button_type='backSmall', 152 position=(70 + x_offs, self._height - 78), 153 size=(60, 60), 154 label=bui.charstr(bui.SpecialChar.BACK), 155 ) 156 157 condensed = uiscale is not bui.UIScale.LARGE 158 t_offs_y = ( 159 0 if not condensed else 25 if uiscale is bui.UIScale.MEDIUM else 17 160 ) 161 bui.textwidget( 162 parent=self._root_widget, 163 position=(self._width * 0.5, self._height - 42 + t_offs_y), 164 size=(0, 0), 165 color=bui.app.ui_v1.title_color, 166 scale=( 167 1.5 168 if not condensed 169 else 1.0 170 if uiscale is bui.UIScale.MEDIUM 171 else 0.6 172 ), 173 h_align='center', 174 v_align='center', 175 text=bui.Lstr(resource=self._r + '.titleText'), 176 maxwidth=550, 177 ) 178 179 scroll_buffer_h = 130 + 2 * x_offs 180 tab_buffer_h = (320 if condensed else 250) + 2 * x_offs 181 182 # Build up the set of tabs we want. 183 tabdefs: list[tuple[GatherWindow.TabID, bui.Lstr]] = [ 184 (self.TabID.ABOUT, bui.Lstr(resource=self._r + '.aboutText')) 185 ] 186 if plus.get_v1_account_misc_read_val('enablePublicParties', True): 187 tabdefs.append( 188 ( 189 self.TabID.INTERNET, 190 bui.Lstr(resource=self._r + '.publicText'), 191 ) 192 ) 193 tabdefs.append( 194 (self.TabID.PRIVATE, bui.Lstr(resource=self._r + '.privateText')) 195 ) 196 tabdefs.append( 197 (self.TabID.NEARBY, bui.Lstr(resource=self._r + '.nearbyText')) 198 ) 199 tabdefs.append( 200 (self.TabID.MANUAL, bui.Lstr(resource=self._r + '.manualText')) 201 ) 202 203 # On small UI, push our tabs up closer to the top of the screen to 204 # save a bit of space. 205 tabs_top_extra = 42 if condensed else 0 206 self._tab_row = TabRow( 207 self._root_widget, 208 tabdefs, 209 pos=(tab_buffer_h * 0.5, self._height - 130 + tabs_top_extra), 210 size=(self._width - tab_buffer_h, 50), 211 on_select_call=bui.WeakCall(self._set_tab), 212 ) 213 214 # Now instantiate handlers for these tabs. 215 tabtypes: dict[GatherWindow.TabID, type[GatherTab]] = { 216 self.TabID.ABOUT: AboutGatherTab, 217 self.TabID.MANUAL: ManualGatherTab, 218 self.TabID.PRIVATE: PrivateGatherTab, 219 self.TabID.INTERNET: PublicGatherTab, 220 self.TabID.NEARBY: NearbyGatherTab, 221 } 222 self._tabs: dict[GatherWindow.TabID, GatherTab] = {} 223 for tab_id in self._tab_row.tabs: 224 tabtype = tabtypes.get(tab_id) 225 if tabtype is not None: 226 self._tabs[tab_id] = tabtype(self) 227 228 if bui.app.ui_v1.use_toolbars: 229 bui.widget( 230 edit=self._tab_row.tabs[tabdefs[-1][0]].button, 231 right_widget=bui.get_special_widget('party_button'), 232 ) 233 if uiscale is bui.UIScale.SMALL: 234 bui.widget( 235 edit=self._tab_row.tabs[tabdefs[0][0]].button, 236 left_widget=bui.get_special_widget('back_button'), 237 ) 238 239 self._scroll_width = self._width - scroll_buffer_h 240 self._scroll_height = self._height - 180.0 + tabs_top_extra 241 242 self._scroll_left = (self._width - self._scroll_width) * 0.5 243 self._scroll_bottom = ( 244 self._height - self._scroll_height - 79 - 48 + tabs_top_extra 245 ) 246 buffer_h = 10 247 buffer_v = 4 248 249 # Not actually using a scroll widget anymore; just an image. 250 bui.imagewidget( 251 parent=self._root_widget, 252 position=( 253 self._scroll_left - buffer_h, 254 self._scroll_bottom - buffer_v, 255 ), 256 size=( 257 self._scroll_width + 2 * buffer_h, 258 self._scroll_height + 2 * buffer_v, 259 ), 260 texture=bui.gettexture('scrollWidget'), 261 mesh_transparent=bui.getmesh('softEdgeOutside'), 262 ) 263 self._tab_container: bui.Widget | None = None 264 265 self._restore_state()
def
playlist_select(self, origin_widget: _bauiv1.Widget) -> None:
270 def playlist_select(self, origin_widget: bui.Widget) -> None: 271 """Called by the private-hosting tab to select a playlist.""" 272 from bauiv1lib.play import PlayWindow 273 274 self._save_state() 275 bui.containerwidget(edit=self._root_widget, transition='out_left') 276 assert bui.app.classic is not None 277 bui.app.ui_v1.selecting_private_party_playlist = True 278 bui.app.ui_v1.set_main_menu_window( 279 PlayWindow(origin_widget=origin_widget).get_root_widget() 280 )
Called by the private-hosting tab to select a playlist.
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget
class
GatherWindow.TabID(enum.Enum):
59 class TabID(Enum): 60 """Our available tab types.""" 61 62 ABOUT = 'about' 63 INTERNET = 'internet' 64 PRIVATE = 'private' 65 NEARBY = 'nearby' 66 MANUAL = 'manual'
Our available tab types.
Inherited Members
- enum.Enum
- name
- value