bauiv1lib.playlist.addgame
Provides a window for selecting a game type to add to a playlist.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a window for selecting a game type to add to a playlist.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING, override 8 9import bascenev1 as bs 10import bauiv1 as bui 11 12if TYPE_CHECKING: 13 from bauiv1lib.playlist.editcontroller import PlaylistEditController 14 15 16class PlaylistAddGameWindow(bui.MainWindow): 17 """Window for selecting a game type to add to a playlist.""" 18 19 def __init__( 20 self, 21 editcontroller: PlaylistEditController, 22 transition: str | None = 'in_right', 23 origin_widget: bui.Widget | None = None, 24 ): 25 self._editcontroller = editcontroller 26 self._r = 'addGameWindow' 27 assert bui.app.classic is not None 28 uiscale = bui.app.ui_v1.uiscale 29 self._width = 900 if uiscale is bui.UIScale.SMALL else 650 30 31 self._height = ( 32 1200.0 33 if uiscale is bui.UIScale.SMALL 34 else 450.0 if uiscale is bui.UIScale.MEDIUM else 500.0 35 ) 36 self._scroll_width = 210 37 38 # Do some fancy math to fill all available screen area up to the 39 # size of our backing container. This lets us fit to the exact 40 # screen shape at small ui scale. 41 screensize = bui.get_virtual_screen_size() 42 scale = ( 43 2.4 44 if uiscale is bui.UIScale.SMALL 45 else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0 46 ) 47 # Calc screen size in our local container space and clamp to a 48 # bit smaller than our container size. 49 target_width = min(self._width - 50, screensize[0] / scale) 50 target_height = min(self._height - 70, screensize[1] / scale) 51 52 # To get top/left coords, go to the center of our window and 53 # offset by half the width/height of our target area. 54 yoffs = 0.5 * self._height + 0.5 * target_height + 5.0 55 x_inset = 0.5 * self._width - 0.5 * target_width 56 57 super().__init__( 58 root_widget=bui.containerwidget( 59 size=(self._width, self._height), 60 scale=scale, 61 toolbar_visibility='menu_minimal', 62 ), 63 transition=transition, 64 origin_widget=origin_widget, 65 # We're affected by screen size only at small ui-scale. 66 refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, 67 ) 68 69 if uiscale is bui.UIScale.SMALL: 70 self._back_button = bui.get_special_widget('back_button') 71 else: 72 self._back_button = bui.buttonwidget( 73 parent=self._root_widget, 74 position=(58 + x_inset, yoffs - 53), 75 size=(60, 48), 76 label=bui.charstr(bui.SpecialChar.BACK), 77 autoselect=True, 78 button_type='backSmall', 79 on_activate_call=self.main_window_back, 80 ) 81 82 self._select_button = select_button = bui.buttonwidget( 83 parent=self._root_widget, 84 position=( 85 x_inset + target_width - 172, 86 yoffs - 50, 87 ), 88 autoselect=True, 89 size=(160, 60), 90 scale=0.75, 91 text_scale=1.2, 92 label=bui.Lstr(resource='selectText'), 93 on_activate_call=self._add, 94 ) 95 96 bui.widget( 97 edit=select_button, 98 right_widget=bui.get_special_widget('squad_button'), 99 ) 100 101 bui.textwidget( 102 parent=self._root_widget, 103 position=(self._width * 0.5, yoffs - 28), 104 size=(0, 0), 105 scale=1.0, 106 text=bui.Lstr(resource=f'{self._r}.titleText'), 107 h_align='center', 108 color=bui.app.ui_v1.title_color, 109 maxwidth=250, 110 v_align='center', 111 ) 112 v = yoffs - 64 113 114 self._selected_title_text = bui.textwidget( 115 parent=self._root_widget, 116 position=(x_inset + self._scroll_width + 50 + 30, v - 15), 117 size=(0, 0), 118 scale=1.0, 119 color=(0.7, 1.0, 0.7, 1.0), 120 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 121 h_align='left', 122 v_align='center', 123 ) 124 v -= 30 125 126 self._selected_description_text = bui.textwidget( 127 parent=self._root_widget, 128 position=(x_inset + self._scroll_width + 50 + 30, v), 129 size=(0, 0), 130 scale=0.7, 131 color=(0.5, 0.8, 0.5, 1.0), 132 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 133 h_align='left', 134 ) 135 136 scroll_height = target_height - 60 137 138 v = yoffs - 60 139 140 self._scrollwidget = bui.scrollwidget( 141 parent=self._root_widget, 142 position=(x_inset + 61, v - scroll_height), 143 size=(self._scroll_width, scroll_height), 144 highlight=False, 145 border_opacity=0.4, 146 ) 147 bui.widget( 148 edit=self._scrollwidget, 149 up_widget=self._back_button, 150 left_widget=self._back_button, 151 right_widget=select_button, 152 ) 153 self._column: bui.Widget | None = None 154 155 v -= 35 156 157 if uiscale is bui.UIScale.SMALL: 158 bui.containerwidget( 159 edit=self._root_widget, on_cancel_call=self.main_window_back 160 ) 161 else: 162 bui.containerwidget( 163 edit=self._root_widget, 164 cancel_button=self._back_button, 165 ) 166 bui.containerwidget(edit=self._root_widget, start_button=select_button) 167 168 self._selected_game_type: type[bs.GameActivity] | None = None 169 170 bui.containerwidget( 171 edit=self._root_widget, selected_child=self._scrollwidget 172 ) 173 174 self._game_types: list[type[bs.GameActivity]] = [] 175 176 # Get actual games loading in the bg. 177 bui.app.meta.load_exported_classes( 178 bs.GameActivity, 179 self._on_game_types_loaded, 180 completion_cb_in_bg_thread=True, 181 ) 182 183 # Refresh with our initial empty list. We'll refresh again once 184 # game loading is complete. 185 self._refresh() 186 187 @override 188 def get_main_window_state(self) -> bui.MainWindowState: 189 # Support recreating our window for back/refresh purposes. 190 cls = type(self) 191 192 # Avoid dereferencing self from the lambda or we'll keep 193 # ourself alive indefinitely. 194 editcontroller = self._editcontroller 195 196 return bui.BasicMainWindowState( 197 create_call=lambda transition, origin_widget: cls( 198 transition=transition, 199 origin_widget=origin_widget, 200 editcontroller=editcontroller, 201 ) 202 ) 203 204 def _on_game_types_loaded( 205 self, gametypes: list[type[bs.GameActivity]] 206 ) -> None: 207 assert bui.app.classic is not None 208 store = bui.app.classic.store 209 210 # We asked for a bg thread completion cb so we can do some 211 # filtering here in the bg thread where its not gonna cause hitches. 212 assert not bui.in_logic_thread() 213 sessiontype = self._editcontroller.get_session_type() 214 unowned = store.get_unowned_game_types() 215 self._game_types = [ 216 gt 217 for gt in gametypes 218 if gt not in unowned and gt.supports_session_type(sessiontype) 219 ] 220 221 # Sort in the current language. 222 self._game_types.sort(key=lambda g: g.get_display_string().evaluate()) 223 224 # Tell ourself to refresh back in the logic thread. 225 bui.pushcall(self._refresh, from_other_thread=True) 226 227 def _refresh(self, select_get_more_games_button: bool = False) -> None: 228 if self._column is not None: 229 self._column.delete() 230 231 self._column = bui.columnwidget( 232 parent=self._scrollwidget, border=2, margin=0 233 ) 234 235 for i, gametype in enumerate(self._game_types): 236 237 def _doit() -> None: 238 if self._select_button: 239 bui.apptimer(0.1, self._select_button.activate) 240 241 txt = bui.textwidget( 242 parent=self._column, 243 position=(0, 0), 244 size=(self._scroll_width * 1.1, 24), 245 text=gametype.get_display_string(), 246 h_align='left', 247 v_align='center', 248 color=(0.8, 0.8, 0.8, 1.0), 249 maxwidth=self._scroll_width * 0.8, 250 on_select_call=bui.Call(self._set_selected_game_type, gametype), 251 always_highlight=True, 252 selectable=True, 253 on_activate_call=_doit, 254 ) 255 if i == 0: 256 bui.widget(edit=txt, up_widget=self._back_button) 257 258 self._get_more_games_button = bui.buttonwidget( 259 parent=self._column, 260 autoselect=True, 261 label=bui.Lstr(resource=f'{self._r}.getMoreGamesText'), 262 color=(0.54, 0.52, 0.67), 263 textcolor=(0.7, 0.65, 0.7), 264 on_activate_call=self._on_get_more_games_press, 265 size=(178, 50), 266 ) 267 if select_get_more_games_button: 268 bui.containerwidget( 269 edit=self._column, 270 selected_child=self._get_more_games_button, 271 visible_child=self._get_more_games_button, 272 ) 273 274 def _on_get_more_games_press(self) -> None: 275 from bauiv1lib.account.signin import show_sign_in_prompt 276 from bauiv1lib.store.browser import StoreBrowserWindow 277 278 # No-op if we're not in control. 279 if not self.main_window_has_control(): 280 return 281 282 plus = bui.app.plus 283 assert plus is not None 284 285 if plus.get_v1_account_state() != 'signed_in': 286 show_sign_in_prompt() 287 return 288 289 self.main_window_replace( 290 StoreBrowserWindow( 291 show_tab=StoreBrowserWindow.TabID.MINIGAMES, 292 origin_widget=self._get_more_games_button, 293 minimal_toolbars=True, 294 ) 295 ) 296 297 def _add(self) -> None: 298 bui.lock_all_input() # Make sure no more commands happen. 299 bui.apptimer(0.1, bui.unlock_all_input) 300 assert self._selected_game_type is not None 301 self._editcontroller.add_game_type_selected( 302 self._selected_game_type, from_window=self 303 ) 304 305 def _set_selected_game_type(self, gametype: type[bs.GameActivity]) -> None: 306 self._selected_game_type = gametype 307 bui.textwidget( 308 edit=self._selected_title_text, text=gametype.get_display_string() 309 ) 310 bui.textwidget( 311 edit=self._selected_description_text, 312 text=gametype.get_description_display_string( 313 self._editcontroller.get_session_type() 314 ), 315 )
class
PlaylistAddGameWindow(bauiv1._uitypes.MainWindow):
17class PlaylistAddGameWindow(bui.MainWindow): 18 """Window for selecting a game type to add to a playlist.""" 19 20 def __init__( 21 self, 22 editcontroller: PlaylistEditController, 23 transition: str | None = 'in_right', 24 origin_widget: bui.Widget | None = None, 25 ): 26 self._editcontroller = editcontroller 27 self._r = 'addGameWindow' 28 assert bui.app.classic is not None 29 uiscale = bui.app.ui_v1.uiscale 30 self._width = 900 if uiscale is bui.UIScale.SMALL else 650 31 32 self._height = ( 33 1200.0 34 if uiscale is bui.UIScale.SMALL 35 else 450.0 if uiscale is bui.UIScale.MEDIUM else 500.0 36 ) 37 self._scroll_width = 210 38 39 # Do some fancy math to fill all available screen area up to the 40 # size of our backing container. This lets us fit to the exact 41 # screen shape at small ui scale. 42 screensize = bui.get_virtual_screen_size() 43 scale = ( 44 2.4 45 if uiscale is bui.UIScale.SMALL 46 else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0 47 ) 48 # Calc screen size in our local container space and clamp to a 49 # bit smaller than our container size. 50 target_width = min(self._width - 50, screensize[0] / scale) 51 target_height = min(self._height - 70, screensize[1] / scale) 52 53 # To get top/left coords, go to the center of our window and 54 # offset by half the width/height of our target area. 55 yoffs = 0.5 * self._height + 0.5 * target_height + 5.0 56 x_inset = 0.5 * self._width - 0.5 * target_width 57 58 super().__init__( 59 root_widget=bui.containerwidget( 60 size=(self._width, self._height), 61 scale=scale, 62 toolbar_visibility='menu_minimal', 63 ), 64 transition=transition, 65 origin_widget=origin_widget, 66 # We're affected by screen size only at small ui-scale. 67 refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, 68 ) 69 70 if uiscale is bui.UIScale.SMALL: 71 self._back_button = bui.get_special_widget('back_button') 72 else: 73 self._back_button = bui.buttonwidget( 74 parent=self._root_widget, 75 position=(58 + x_inset, yoffs - 53), 76 size=(60, 48), 77 label=bui.charstr(bui.SpecialChar.BACK), 78 autoselect=True, 79 button_type='backSmall', 80 on_activate_call=self.main_window_back, 81 ) 82 83 self._select_button = select_button = bui.buttonwidget( 84 parent=self._root_widget, 85 position=( 86 x_inset + target_width - 172, 87 yoffs - 50, 88 ), 89 autoselect=True, 90 size=(160, 60), 91 scale=0.75, 92 text_scale=1.2, 93 label=bui.Lstr(resource='selectText'), 94 on_activate_call=self._add, 95 ) 96 97 bui.widget( 98 edit=select_button, 99 right_widget=bui.get_special_widget('squad_button'), 100 ) 101 102 bui.textwidget( 103 parent=self._root_widget, 104 position=(self._width * 0.5, yoffs - 28), 105 size=(0, 0), 106 scale=1.0, 107 text=bui.Lstr(resource=f'{self._r}.titleText'), 108 h_align='center', 109 color=bui.app.ui_v1.title_color, 110 maxwidth=250, 111 v_align='center', 112 ) 113 v = yoffs - 64 114 115 self._selected_title_text = bui.textwidget( 116 parent=self._root_widget, 117 position=(x_inset + self._scroll_width + 50 + 30, v - 15), 118 size=(0, 0), 119 scale=1.0, 120 color=(0.7, 1.0, 0.7, 1.0), 121 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 122 h_align='left', 123 v_align='center', 124 ) 125 v -= 30 126 127 self._selected_description_text = bui.textwidget( 128 parent=self._root_widget, 129 position=(x_inset + self._scroll_width + 50 + 30, v), 130 size=(0, 0), 131 scale=0.7, 132 color=(0.5, 0.8, 0.5, 1.0), 133 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 134 h_align='left', 135 ) 136 137 scroll_height = target_height - 60 138 139 v = yoffs - 60 140 141 self._scrollwidget = bui.scrollwidget( 142 parent=self._root_widget, 143 position=(x_inset + 61, v - scroll_height), 144 size=(self._scroll_width, scroll_height), 145 highlight=False, 146 border_opacity=0.4, 147 ) 148 bui.widget( 149 edit=self._scrollwidget, 150 up_widget=self._back_button, 151 left_widget=self._back_button, 152 right_widget=select_button, 153 ) 154 self._column: bui.Widget | None = None 155 156 v -= 35 157 158 if uiscale is bui.UIScale.SMALL: 159 bui.containerwidget( 160 edit=self._root_widget, on_cancel_call=self.main_window_back 161 ) 162 else: 163 bui.containerwidget( 164 edit=self._root_widget, 165 cancel_button=self._back_button, 166 ) 167 bui.containerwidget(edit=self._root_widget, start_button=select_button) 168 169 self._selected_game_type: type[bs.GameActivity] | None = None 170 171 bui.containerwidget( 172 edit=self._root_widget, selected_child=self._scrollwidget 173 ) 174 175 self._game_types: list[type[bs.GameActivity]] = [] 176 177 # Get actual games loading in the bg. 178 bui.app.meta.load_exported_classes( 179 bs.GameActivity, 180 self._on_game_types_loaded, 181 completion_cb_in_bg_thread=True, 182 ) 183 184 # Refresh with our initial empty list. We'll refresh again once 185 # game loading is complete. 186 self._refresh() 187 188 @override 189 def get_main_window_state(self) -> bui.MainWindowState: 190 # Support recreating our window for back/refresh purposes. 191 cls = type(self) 192 193 # Avoid dereferencing self from the lambda or we'll keep 194 # ourself alive indefinitely. 195 editcontroller = self._editcontroller 196 197 return bui.BasicMainWindowState( 198 create_call=lambda transition, origin_widget: cls( 199 transition=transition, 200 origin_widget=origin_widget, 201 editcontroller=editcontroller, 202 ) 203 ) 204 205 def _on_game_types_loaded( 206 self, gametypes: list[type[bs.GameActivity]] 207 ) -> None: 208 assert bui.app.classic is not None 209 store = bui.app.classic.store 210 211 # We asked for a bg thread completion cb so we can do some 212 # filtering here in the bg thread where its not gonna cause hitches. 213 assert not bui.in_logic_thread() 214 sessiontype = self._editcontroller.get_session_type() 215 unowned = store.get_unowned_game_types() 216 self._game_types = [ 217 gt 218 for gt in gametypes 219 if gt not in unowned and gt.supports_session_type(sessiontype) 220 ] 221 222 # Sort in the current language. 223 self._game_types.sort(key=lambda g: g.get_display_string().evaluate()) 224 225 # Tell ourself to refresh back in the logic thread. 226 bui.pushcall(self._refresh, from_other_thread=True) 227 228 def _refresh(self, select_get_more_games_button: bool = False) -> None: 229 if self._column is not None: 230 self._column.delete() 231 232 self._column = bui.columnwidget( 233 parent=self._scrollwidget, border=2, margin=0 234 ) 235 236 for i, gametype in enumerate(self._game_types): 237 238 def _doit() -> None: 239 if self._select_button: 240 bui.apptimer(0.1, self._select_button.activate) 241 242 txt = bui.textwidget( 243 parent=self._column, 244 position=(0, 0), 245 size=(self._scroll_width * 1.1, 24), 246 text=gametype.get_display_string(), 247 h_align='left', 248 v_align='center', 249 color=(0.8, 0.8, 0.8, 1.0), 250 maxwidth=self._scroll_width * 0.8, 251 on_select_call=bui.Call(self._set_selected_game_type, gametype), 252 always_highlight=True, 253 selectable=True, 254 on_activate_call=_doit, 255 ) 256 if i == 0: 257 bui.widget(edit=txt, up_widget=self._back_button) 258 259 self._get_more_games_button = bui.buttonwidget( 260 parent=self._column, 261 autoselect=True, 262 label=bui.Lstr(resource=f'{self._r}.getMoreGamesText'), 263 color=(0.54, 0.52, 0.67), 264 textcolor=(0.7, 0.65, 0.7), 265 on_activate_call=self._on_get_more_games_press, 266 size=(178, 50), 267 ) 268 if select_get_more_games_button: 269 bui.containerwidget( 270 edit=self._column, 271 selected_child=self._get_more_games_button, 272 visible_child=self._get_more_games_button, 273 ) 274 275 def _on_get_more_games_press(self) -> None: 276 from bauiv1lib.account.signin import show_sign_in_prompt 277 from bauiv1lib.store.browser import StoreBrowserWindow 278 279 # No-op if we're not in control. 280 if not self.main_window_has_control(): 281 return 282 283 plus = bui.app.plus 284 assert plus is not None 285 286 if plus.get_v1_account_state() != 'signed_in': 287 show_sign_in_prompt() 288 return 289 290 self.main_window_replace( 291 StoreBrowserWindow( 292 show_tab=StoreBrowserWindow.TabID.MINIGAMES, 293 origin_widget=self._get_more_games_button, 294 minimal_toolbars=True, 295 ) 296 ) 297 298 def _add(self) -> None: 299 bui.lock_all_input() # Make sure no more commands happen. 300 bui.apptimer(0.1, bui.unlock_all_input) 301 assert self._selected_game_type is not None 302 self._editcontroller.add_game_type_selected( 303 self._selected_game_type, from_window=self 304 ) 305 306 def _set_selected_game_type(self, gametype: type[bs.GameActivity]) -> None: 307 self._selected_game_type = gametype 308 bui.textwidget( 309 edit=self._selected_title_text, text=gametype.get_display_string() 310 ) 311 bui.textwidget( 312 edit=self._selected_description_text, 313 text=gametype.get_description_display_string( 314 self._editcontroller.get_session_type() 315 ), 316 )
Window for selecting a game type to add to a playlist.
PlaylistAddGameWindow( editcontroller: bauiv1lib.playlist.editcontroller.PlaylistEditController, transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
20 def __init__( 21 self, 22 editcontroller: PlaylistEditController, 23 transition: str | None = 'in_right', 24 origin_widget: bui.Widget | None = None, 25 ): 26 self._editcontroller = editcontroller 27 self._r = 'addGameWindow' 28 assert bui.app.classic is not None 29 uiscale = bui.app.ui_v1.uiscale 30 self._width = 900 if uiscale is bui.UIScale.SMALL else 650 31 32 self._height = ( 33 1200.0 34 if uiscale is bui.UIScale.SMALL 35 else 450.0 if uiscale is bui.UIScale.MEDIUM else 500.0 36 ) 37 self._scroll_width = 210 38 39 # Do some fancy math to fill all available screen area up to the 40 # size of our backing container. This lets us fit to the exact 41 # screen shape at small ui scale. 42 screensize = bui.get_virtual_screen_size() 43 scale = ( 44 2.4 45 if uiscale is bui.UIScale.SMALL 46 else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0 47 ) 48 # Calc screen size in our local container space and clamp to a 49 # bit smaller than our container size. 50 target_width = min(self._width - 50, screensize[0] / scale) 51 target_height = min(self._height - 70, screensize[1] / scale) 52 53 # To get top/left coords, go to the center of our window and 54 # offset by half the width/height of our target area. 55 yoffs = 0.5 * self._height + 0.5 * target_height + 5.0 56 x_inset = 0.5 * self._width - 0.5 * target_width 57 58 super().__init__( 59 root_widget=bui.containerwidget( 60 size=(self._width, self._height), 61 scale=scale, 62 toolbar_visibility='menu_minimal', 63 ), 64 transition=transition, 65 origin_widget=origin_widget, 66 # We're affected by screen size only at small ui-scale. 67 refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, 68 ) 69 70 if uiscale is bui.UIScale.SMALL: 71 self._back_button = bui.get_special_widget('back_button') 72 else: 73 self._back_button = bui.buttonwidget( 74 parent=self._root_widget, 75 position=(58 + x_inset, yoffs - 53), 76 size=(60, 48), 77 label=bui.charstr(bui.SpecialChar.BACK), 78 autoselect=True, 79 button_type='backSmall', 80 on_activate_call=self.main_window_back, 81 ) 82 83 self._select_button = select_button = bui.buttonwidget( 84 parent=self._root_widget, 85 position=( 86 x_inset + target_width - 172, 87 yoffs - 50, 88 ), 89 autoselect=True, 90 size=(160, 60), 91 scale=0.75, 92 text_scale=1.2, 93 label=bui.Lstr(resource='selectText'), 94 on_activate_call=self._add, 95 ) 96 97 bui.widget( 98 edit=select_button, 99 right_widget=bui.get_special_widget('squad_button'), 100 ) 101 102 bui.textwidget( 103 parent=self._root_widget, 104 position=(self._width * 0.5, yoffs - 28), 105 size=(0, 0), 106 scale=1.0, 107 text=bui.Lstr(resource=f'{self._r}.titleText'), 108 h_align='center', 109 color=bui.app.ui_v1.title_color, 110 maxwidth=250, 111 v_align='center', 112 ) 113 v = yoffs - 64 114 115 self._selected_title_text = bui.textwidget( 116 parent=self._root_widget, 117 position=(x_inset + self._scroll_width + 50 + 30, v - 15), 118 size=(0, 0), 119 scale=1.0, 120 color=(0.7, 1.0, 0.7, 1.0), 121 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 122 h_align='left', 123 v_align='center', 124 ) 125 v -= 30 126 127 self._selected_description_text = bui.textwidget( 128 parent=self._root_widget, 129 position=(x_inset + self._scroll_width + 50 + 30, v), 130 size=(0, 0), 131 scale=0.7, 132 color=(0.5, 0.8, 0.5, 1.0), 133 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 134 h_align='left', 135 ) 136 137 scroll_height = target_height - 60 138 139 v = yoffs - 60 140 141 self._scrollwidget = bui.scrollwidget( 142 parent=self._root_widget, 143 position=(x_inset + 61, v - scroll_height), 144 size=(self._scroll_width, scroll_height), 145 highlight=False, 146 border_opacity=0.4, 147 ) 148 bui.widget( 149 edit=self._scrollwidget, 150 up_widget=self._back_button, 151 left_widget=self._back_button, 152 right_widget=select_button, 153 ) 154 self._column: bui.Widget | None = None 155 156 v -= 35 157 158 if uiscale is bui.UIScale.SMALL: 159 bui.containerwidget( 160 edit=self._root_widget, on_cancel_call=self.main_window_back 161 ) 162 else: 163 bui.containerwidget( 164 edit=self._root_widget, 165 cancel_button=self._back_button, 166 ) 167 bui.containerwidget(edit=self._root_widget, start_button=select_button) 168 169 self._selected_game_type: type[bs.GameActivity] | None = None 170 171 bui.containerwidget( 172 edit=self._root_widget, selected_child=self._scrollwidget 173 ) 174 175 self._game_types: list[type[bs.GameActivity]] = [] 176 177 # Get actual games loading in the bg. 178 bui.app.meta.load_exported_classes( 179 bs.GameActivity, 180 self._on_game_types_loaded, 181 completion_cb_in_bg_thread=True, 182 ) 183 184 # Refresh with our initial empty list. We'll refresh again once 185 # game loading is complete. 186 self._refresh()
Create a MainWindow given a root widget and transition info.
Automatically handles in and out transitions on the provided widget, so there is no need to set transitions when creating it.
188 @override 189 def get_main_window_state(self) -> bui.MainWindowState: 190 # Support recreating our window for back/refresh purposes. 191 cls = type(self) 192 193 # Avoid dereferencing self from the lambda or we'll keep 194 # ourself alive indefinitely. 195 editcontroller = self._editcontroller 196 197 return bui.BasicMainWindowState( 198 create_call=lambda transition, origin_widget: cls( 199 transition=transition, 200 origin_widget=origin_widget, 201 editcontroller=editcontroller, 202 ) 203 )
Return a WindowState to recreate this window, if supported.