bastd.ui.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 8 9import ba 10import ba.internal 11 12if TYPE_CHECKING: 13 from bastd.ui.playlist.editcontroller import PlaylistEditController 14 15 16class PlaylistAddGameWindow(ba.Window): 17 """Window for selecting a game type to add to a playlist.""" 18 19 def __init__( 20 self, 21 editcontroller: PlaylistEditController, 22 transition: str = 'in_right', 23 ): 24 self._editcontroller = editcontroller 25 self._r = 'addGameWindow' 26 uiscale = ba.app.ui.uiscale 27 self._width = 750 if uiscale is ba.UIScale.SMALL else 650 28 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 29 self._height = ( 30 346 31 if uiscale is ba.UIScale.SMALL 32 else 380 33 if uiscale is ba.UIScale.MEDIUM 34 else 440 35 ) 36 top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 37 self._scroll_width = 210 38 39 super().__init__( 40 root_widget=ba.containerwidget( 41 size=(self._width, self._height + top_extra), 42 transition=transition, 43 scale=( 44 2.17 45 if uiscale is ba.UIScale.SMALL 46 else 1.5 47 if uiscale is ba.UIScale.MEDIUM 48 else 1.0 49 ), 50 stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0), 51 ) 52 ) 53 54 self._back_button = ba.buttonwidget( 55 parent=self._root_widget, 56 position=(58 + x_inset, self._height - 53), 57 size=(165, 70), 58 scale=0.75, 59 text_scale=1.2, 60 label=ba.Lstr(resource='backText'), 61 autoselect=True, 62 button_type='back', 63 on_activate_call=self._back, 64 ) 65 self._select_button = select_button = ba.buttonwidget( 66 parent=self._root_widget, 67 position=(self._width - (172 + x_inset), self._height - 50), 68 autoselect=True, 69 size=(160, 60), 70 scale=0.75, 71 text_scale=1.2, 72 label=ba.Lstr(resource='selectText'), 73 on_activate_call=self._add, 74 ) 75 76 if ba.app.ui.use_toolbars: 77 ba.widget( 78 edit=select_button, 79 right_widget=ba.internal.get_special_widget('party_button'), 80 ) 81 82 ba.textwidget( 83 parent=self._root_widget, 84 position=(self._width * 0.5, self._height - 28), 85 size=(0, 0), 86 scale=1.0, 87 text=ba.Lstr(resource=self._r + '.titleText'), 88 h_align='center', 89 color=ba.app.ui.title_color, 90 maxwidth=250, 91 v_align='center', 92 ) 93 v = self._height - 64 94 95 self._selected_title_text = ba.textwidget( 96 parent=self._root_widget, 97 position=(x_inset + self._scroll_width + 50 + 30, v - 15), 98 size=(0, 0), 99 scale=1.0, 100 color=(0.7, 1.0, 0.7, 1.0), 101 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 102 h_align='left', 103 v_align='center', 104 ) 105 v -= 30 106 107 self._selected_description_text = ba.textwidget( 108 parent=self._root_widget, 109 position=(x_inset + self._scroll_width + 50 + 30, v), 110 size=(0, 0), 111 scale=0.7, 112 color=(0.5, 0.8, 0.5, 1.0), 113 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 114 h_align='left', 115 ) 116 117 scroll_height = self._height - 100 118 119 v = self._height - 60 120 121 self._scrollwidget = ba.scrollwidget( 122 parent=self._root_widget, 123 position=(x_inset + 61, v - scroll_height), 124 size=(self._scroll_width, scroll_height), 125 highlight=False, 126 ) 127 ba.widget( 128 edit=self._scrollwidget, 129 up_widget=self._back_button, 130 left_widget=self._back_button, 131 right_widget=select_button, 132 ) 133 self._column: ba.Widget | None = None 134 135 v -= 35 136 ba.containerwidget( 137 edit=self._root_widget, 138 cancel_button=self._back_button, 139 start_button=select_button, 140 ) 141 self._selected_game_type: type[ba.GameActivity] | None = None 142 143 ba.containerwidget( 144 edit=self._root_widget, selected_child=self._scrollwidget 145 ) 146 147 self._game_types: list[type[ba.GameActivity]] = [] 148 149 # Get actual games loading in the bg. 150 ba.app.meta.load_exported_classes( 151 ba.GameActivity, 152 self._on_game_types_loaded, 153 completion_cb_in_bg_thread=True, 154 ) 155 156 # Refresh with our initial empty list. We'll refresh again once 157 # game loading is complete. 158 self._refresh() 159 160 def _on_game_types_loaded( 161 self, gametypes: list[type[ba.GameActivity]] 162 ) -> None: 163 from ba.internal import get_unowned_game_types 164 165 # We asked for a bg thread completion cb so we can do some 166 # filtering here in the bg thread where its not gonna cause hitches. 167 assert not ba.in_logic_thread() 168 sessiontype = self._editcontroller.get_session_type() 169 unowned = get_unowned_game_types() 170 self._game_types = [ 171 gt 172 for gt in gametypes 173 if gt not in unowned and gt.supports_session_type(sessiontype) 174 ] 175 176 # Sort in the current language. 177 self._game_types.sort(key=lambda g: g.get_display_string().evaluate()) 178 179 # Tell ourself to refresh back in the logic thread. 180 ba.pushcall(self._refresh, from_other_thread=True) 181 182 def _refresh(self, select_get_more_games_button: bool = False) -> None: 183 # from ba.internal import get_game_types 184 185 if self._column is not None: 186 self._column.delete() 187 188 self._column = ba.columnwidget( 189 parent=self._scrollwidget, border=2, margin=0 190 ) 191 192 for i, gametype in enumerate(self._game_types): 193 194 def _doit() -> None: 195 if self._select_button: 196 ba.timer( 197 0.1, 198 self._select_button.activate, 199 timetype=ba.TimeType.REAL, 200 ) 201 202 txt = ba.textwidget( 203 parent=self._column, 204 position=(0, 0), 205 size=(self._width - 88, 24), 206 text=gametype.get_display_string(), 207 h_align='left', 208 v_align='center', 209 color=(0.8, 0.8, 0.8, 1.0), 210 maxwidth=self._scroll_width * 0.8, 211 on_select_call=ba.Call(self._set_selected_game_type, gametype), 212 always_highlight=True, 213 selectable=True, 214 on_activate_call=_doit, 215 ) 216 if i == 0: 217 ba.widget(edit=txt, up_widget=self._back_button) 218 219 self._get_more_games_button = ba.buttonwidget( 220 parent=self._column, 221 autoselect=True, 222 label=ba.Lstr(resource=self._r + '.getMoreGamesText'), 223 color=(0.54, 0.52, 0.67), 224 textcolor=(0.7, 0.65, 0.7), 225 on_activate_call=self._on_get_more_games_press, 226 size=(178, 50), 227 ) 228 if select_get_more_games_button: 229 ba.containerwidget( 230 edit=self._column, 231 selected_child=self._get_more_games_button, 232 visible_child=self._get_more_games_button, 233 ) 234 235 def _on_get_more_games_press(self) -> None: 236 from bastd.ui.account import show_sign_in_prompt 237 from bastd.ui.store.browser import StoreBrowserWindow 238 239 if ba.internal.get_v1_account_state() != 'signed_in': 240 show_sign_in_prompt() 241 return 242 StoreBrowserWindow( 243 modal=True, 244 show_tab=StoreBrowserWindow.TabID.MINIGAMES, 245 on_close_call=self._on_store_close, 246 origin_widget=self._get_more_games_button, 247 ) 248 249 def _on_store_close(self) -> None: 250 self._refresh(select_get_more_games_button=True) 251 252 def _add(self) -> None: 253 ba.internal.lock_all_input() # Make sure no more commands happen. 254 ba.timer(0.1, ba.internal.unlock_all_input, timetype=ba.TimeType.REAL) 255 assert self._selected_game_type is not None 256 self._editcontroller.add_game_type_selected(self._selected_game_type) 257 258 def _set_selected_game_type(self, gametype: type[ba.GameActivity]) -> None: 259 self._selected_game_type = gametype 260 ba.textwidget( 261 edit=self._selected_title_text, text=gametype.get_display_string() 262 ) 263 ba.textwidget( 264 edit=self._selected_description_text, 265 text=gametype.get_description_display_string( 266 self._editcontroller.get_session_type() 267 ), 268 ) 269 270 def _back(self) -> None: 271 self._editcontroller.add_game_cancelled()
class
PlaylistAddGameWindow(ba.ui.Window):
17class PlaylistAddGameWindow(ba.Window): 18 """Window for selecting a game type to add to a playlist.""" 19 20 def __init__( 21 self, 22 editcontroller: PlaylistEditController, 23 transition: str = 'in_right', 24 ): 25 self._editcontroller = editcontroller 26 self._r = 'addGameWindow' 27 uiscale = ba.app.ui.uiscale 28 self._width = 750 if uiscale is ba.UIScale.SMALL else 650 29 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 30 self._height = ( 31 346 32 if uiscale is ba.UIScale.SMALL 33 else 380 34 if uiscale is ba.UIScale.MEDIUM 35 else 440 36 ) 37 top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 38 self._scroll_width = 210 39 40 super().__init__( 41 root_widget=ba.containerwidget( 42 size=(self._width, self._height + top_extra), 43 transition=transition, 44 scale=( 45 2.17 46 if uiscale is ba.UIScale.SMALL 47 else 1.5 48 if uiscale is ba.UIScale.MEDIUM 49 else 1.0 50 ), 51 stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0), 52 ) 53 ) 54 55 self._back_button = ba.buttonwidget( 56 parent=self._root_widget, 57 position=(58 + x_inset, self._height - 53), 58 size=(165, 70), 59 scale=0.75, 60 text_scale=1.2, 61 label=ba.Lstr(resource='backText'), 62 autoselect=True, 63 button_type='back', 64 on_activate_call=self._back, 65 ) 66 self._select_button = select_button = ba.buttonwidget( 67 parent=self._root_widget, 68 position=(self._width - (172 + x_inset), self._height - 50), 69 autoselect=True, 70 size=(160, 60), 71 scale=0.75, 72 text_scale=1.2, 73 label=ba.Lstr(resource='selectText'), 74 on_activate_call=self._add, 75 ) 76 77 if ba.app.ui.use_toolbars: 78 ba.widget( 79 edit=select_button, 80 right_widget=ba.internal.get_special_widget('party_button'), 81 ) 82 83 ba.textwidget( 84 parent=self._root_widget, 85 position=(self._width * 0.5, self._height - 28), 86 size=(0, 0), 87 scale=1.0, 88 text=ba.Lstr(resource=self._r + '.titleText'), 89 h_align='center', 90 color=ba.app.ui.title_color, 91 maxwidth=250, 92 v_align='center', 93 ) 94 v = self._height - 64 95 96 self._selected_title_text = ba.textwidget( 97 parent=self._root_widget, 98 position=(x_inset + self._scroll_width + 50 + 30, v - 15), 99 size=(0, 0), 100 scale=1.0, 101 color=(0.7, 1.0, 0.7, 1.0), 102 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 103 h_align='left', 104 v_align='center', 105 ) 106 v -= 30 107 108 self._selected_description_text = ba.textwidget( 109 parent=self._root_widget, 110 position=(x_inset + self._scroll_width + 50 + 30, v), 111 size=(0, 0), 112 scale=0.7, 113 color=(0.5, 0.8, 0.5, 1.0), 114 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 115 h_align='left', 116 ) 117 118 scroll_height = self._height - 100 119 120 v = self._height - 60 121 122 self._scrollwidget = ba.scrollwidget( 123 parent=self._root_widget, 124 position=(x_inset + 61, v - scroll_height), 125 size=(self._scroll_width, scroll_height), 126 highlight=False, 127 ) 128 ba.widget( 129 edit=self._scrollwidget, 130 up_widget=self._back_button, 131 left_widget=self._back_button, 132 right_widget=select_button, 133 ) 134 self._column: ba.Widget | None = None 135 136 v -= 35 137 ba.containerwidget( 138 edit=self._root_widget, 139 cancel_button=self._back_button, 140 start_button=select_button, 141 ) 142 self._selected_game_type: type[ba.GameActivity] | None = None 143 144 ba.containerwidget( 145 edit=self._root_widget, selected_child=self._scrollwidget 146 ) 147 148 self._game_types: list[type[ba.GameActivity]] = [] 149 150 # Get actual games loading in the bg. 151 ba.app.meta.load_exported_classes( 152 ba.GameActivity, 153 self._on_game_types_loaded, 154 completion_cb_in_bg_thread=True, 155 ) 156 157 # Refresh with our initial empty list. We'll refresh again once 158 # game loading is complete. 159 self._refresh() 160 161 def _on_game_types_loaded( 162 self, gametypes: list[type[ba.GameActivity]] 163 ) -> None: 164 from ba.internal import get_unowned_game_types 165 166 # We asked for a bg thread completion cb so we can do some 167 # filtering here in the bg thread where its not gonna cause hitches. 168 assert not ba.in_logic_thread() 169 sessiontype = self._editcontroller.get_session_type() 170 unowned = get_unowned_game_types() 171 self._game_types = [ 172 gt 173 for gt in gametypes 174 if gt not in unowned and gt.supports_session_type(sessiontype) 175 ] 176 177 # Sort in the current language. 178 self._game_types.sort(key=lambda g: g.get_display_string().evaluate()) 179 180 # Tell ourself to refresh back in the logic thread. 181 ba.pushcall(self._refresh, from_other_thread=True) 182 183 def _refresh(self, select_get_more_games_button: bool = False) -> None: 184 # from ba.internal import get_game_types 185 186 if self._column is not None: 187 self._column.delete() 188 189 self._column = ba.columnwidget( 190 parent=self._scrollwidget, border=2, margin=0 191 ) 192 193 for i, gametype in enumerate(self._game_types): 194 195 def _doit() -> None: 196 if self._select_button: 197 ba.timer( 198 0.1, 199 self._select_button.activate, 200 timetype=ba.TimeType.REAL, 201 ) 202 203 txt = ba.textwidget( 204 parent=self._column, 205 position=(0, 0), 206 size=(self._width - 88, 24), 207 text=gametype.get_display_string(), 208 h_align='left', 209 v_align='center', 210 color=(0.8, 0.8, 0.8, 1.0), 211 maxwidth=self._scroll_width * 0.8, 212 on_select_call=ba.Call(self._set_selected_game_type, gametype), 213 always_highlight=True, 214 selectable=True, 215 on_activate_call=_doit, 216 ) 217 if i == 0: 218 ba.widget(edit=txt, up_widget=self._back_button) 219 220 self._get_more_games_button = ba.buttonwidget( 221 parent=self._column, 222 autoselect=True, 223 label=ba.Lstr(resource=self._r + '.getMoreGamesText'), 224 color=(0.54, 0.52, 0.67), 225 textcolor=(0.7, 0.65, 0.7), 226 on_activate_call=self._on_get_more_games_press, 227 size=(178, 50), 228 ) 229 if select_get_more_games_button: 230 ba.containerwidget( 231 edit=self._column, 232 selected_child=self._get_more_games_button, 233 visible_child=self._get_more_games_button, 234 ) 235 236 def _on_get_more_games_press(self) -> None: 237 from bastd.ui.account import show_sign_in_prompt 238 from bastd.ui.store.browser import StoreBrowserWindow 239 240 if ba.internal.get_v1_account_state() != 'signed_in': 241 show_sign_in_prompt() 242 return 243 StoreBrowserWindow( 244 modal=True, 245 show_tab=StoreBrowserWindow.TabID.MINIGAMES, 246 on_close_call=self._on_store_close, 247 origin_widget=self._get_more_games_button, 248 ) 249 250 def _on_store_close(self) -> None: 251 self._refresh(select_get_more_games_button=True) 252 253 def _add(self) -> None: 254 ba.internal.lock_all_input() # Make sure no more commands happen. 255 ba.timer(0.1, ba.internal.unlock_all_input, timetype=ba.TimeType.REAL) 256 assert self._selected_game_type is not None 257 self._editcontroller.add_game_type_selected(self._selected_game_type) 258 259 def _set_selected_game_type(self, gametype: type[ba.GameActivity]) -> None: 260 self._selected_game_type = gametype 261 ba.textwidget( 262 edit=self._selected_title_text, text=gametype.get_display_string() 263 ) 264 ba.textwidget( 265 edit=self._selected_description_text, 266 text=gametype.get_description_display_string( 267 self._editcontroller.get_session_type() 268 ), 269 ) 270 271 def _back(self) -> None: 272 self._editcontroller.add_game_cancelled()
Window for selecting a game type to add to a playlist.
PlaylistAddGameWindow( editcontroller: bastd.ui.playlist.editcontroller.PlaylistEditController, transition: str = 'in_right')
20 def __init__( 21 self, 22 editcontroller: PlaylistEditController, 23 transition: str = 'in_right', 24 ): 25 self._editcontroller = editcontroller 26 self._r = 'addGameWindow' 27 uiscale = ba.app.ui.uiscale 28 self._width = 750 if uiscale is ba.UIScale.SMALL else 650 29 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 30 self._height = ( 31 346 32 if uiscale is ba.UIScale.SMALL 33 else 380 34 if uiscale is ba.UIScale.MEDIUM 35 else 440 36 ) 37 top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 38 self._scroll_width = 210 39 40 super().__init__( 41 root_widget=ba.containerwidget( 42 size=(self._width, self._height + top_extra), 43 transition=transition, 44 scale=( 45 2.17 46 if uiscale is ba.UIScale.SMALL 47 else 1.5 48 if uiscale is ba.UIScale.MEDIUM 49 else 1.0 50 ), 51 stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0), 52 ) 53 ) 54 55 self._back_button = ba.buttonwidget( 56 parent=self._root_widget, 57 position=(58 + x_inset, self._height - 53), 58 size=(165, 70), 59 scale=0.75, 60 text_scale=1.2, 61 label=ba.Lstr(resource='backText'), 62 autoselect=True, 63 button_type='back', 64 on_activate_call=self._back, 65 ) 66 self._select_button = select_button = ba.buttonwidget( 67 parent=self._root_widget, 68 position=(self._width - (172 + x_inset), self._height - 50), 69 autoselect=True, 70 size=(160, 60), 71 scale=0.75, 72 text_scale=1.2, 73 label=ba.Lstr(resource='selectText'), 74 on_activate_call=self._add, 75 ) 76 77 if ba.app.ui.use_toolbars: 78 ba.widget( 79 edit=select_button, 80 right_widget=ba.internal.get_special_widget('party_button'), 81 ) 82 83 ba.textwidget( 84 parent=self._root_widget, 85 position=(self._width * 0.5, self._height - 28), 86 size=(0, 0), 87 scale=1.0, 88 text=ba.Lstr(resource=self._r + '.titleText'), 89 h_align='center', 90 color=ba.app.ui.title_color, 91 maxwidth=250, 92 v_align='center', 93 ) 94 v = self._height - 64 95 96 self._selected_title_text = ba.textwidget( 97 parent=self._root_widget, 98 position=(x_inset + self._scroll_width + 50 + 30, v - 15), 99 size=(0, 0), 100 scale=1.0, 101 color=(0.7, 1.0, 0.7, 1.0), 102 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 103 h_align='left', 104 v_align='center', 105 ) 106 v -= 30 107 108 self._selected_description_text = ba.textwidget( 109 parent=self._root_widget, 110 position=(x_inset + self._scroll_width + 50 + 30, v), 111 size=(0, 0), 112 scale=0.7, 113 color=(0.5, 0.8, 0.5, 1.0), 114 maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, 115 h_align='left', 116 ) 117 118 scroll_height = self._height - 100 119 120 v = self._height - 60 121 122 self._scrollwidget = ba.scrollwidget( 123 parent=self._root_widget, 124 position=(x_inset + 61, v - scroll_height), 125 size=(self._scroll_width, scroll_height), 126 highlight=False, 127 ) 128 ba.widget( 129 edit=self._scrollwidget, 130 up_widget=self._back_button, 131 left_widget=self._back_button, 132 right_widget=select_button, 133 ) 134 self._column: ba.Widget | None = None 135 136 v -= 35 137 ba.containerwidget( 138 edit=self._root_widget, 139 cancel_button=self._back_button, 140 start_button=select_button, 141 ) 142 self._selected_game_type: type[ba.GameActivity] | None = None 143 144 ba.containerwidget( 145 edit=self._root_widget, selected_child=self._scrollwidget 146 ) 147 148 self._game_types: list[type[ba.GameActivity]] = [] 149 150 # Get actual games loading in the bg. 151 ba.app.meta.load_exported_classes( 152 ba.GameActivity, 153 self._on_game_types_loaded, 154 completion_cb_in_bg_thread=True, 155 ) 156 157 # Refresh with our initial empty list. We'll refresh again once 158 # game loading is complete. 159 self._refresh()
Inherited Members
- ba.ui.Window
- get_root_widget