bauiv1lib.playlist.edit
Provides a window for editing individual game playlists.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a window for editing individual game playlists.""" 4 5from __future__ import annotations 6 7import logging 8from typing import TYPE_CHECKING, cast 9 10import bascenev1 as bs 11import bauiv1 as bui 12 13if TYPE_CHECKING: 14 from bauiv1lib.playlist.editcontroller import PlaylistEditController 15 16 17class PlaylistEditWindow(bui.Window): 18 """Window for editing an individual game playlist.""" 19 20 def __init__( 21 self, 22 editcontroller: PlaylistEditController, 23 transition: str = 'in_right', 24 ): 25 # pylint: disable=too-many-statements 26 # pylint: disable=too-many-locals 27 prev_selection: str | None 28 self._editcontroller = editcontroller 29 self._r = 'editGameListWindow' 30 prev_selection = self._editcontroller.get_edit_ui_selection() 31 32 assert bui.app.classic is not None 33 uiscale = bui.app.ui_v1.uiscale 34 self._width = 870 if uiscale is bui.UIScale.SMALL else 670 35 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 36 self._height = ( 37 400 38 if uiscale is bui.UIScale.SMALL 39 else 470 if uiscale is bui.UIScale.MEDIUM else 540 40 ) 41 42 top_extra = 20 if uiscale is bui.UIScale.SMALL else 0 43 super().__init__( 44 root_widget=bui.containerwidget( 45 size=(self._width, self._height + top_extra), 46 transition=transition, 47 scale=( 48 2.0 49 if uiscale is bui.UIScale.SMALL 50 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 51 ), 52 stack_offset=( 53 (0, -16) if uiscale is bui.UIScale.SMALL else (0, 0) 54 ), 55 ) 56 ) 57 cancel_button = bui.buttonwidget( 58 parent=self._root_widget, 59 position=(35 + x_inset, self._height - 60), 60 scale=0.8, 61 size=(175, 60), 62 autoselect=True, 63 label=bui.Lstr(resource='cancelText'), 64 text_scale=1.2, 65 ) 66 save_button = btn = bui.buttonwidget( 67 parent=self._root_widget, 68 position=(self._width - (195 + x_inset), self._height - 60), 69 scale=0.8, 70 size=(190, 60), 71 autoselect=True, 72 left_widget=cancel_button, 73 label=bui.Lstr(resource='saveText'), 74 text_scale=1.2, 75 ) 76 77 if bui.app.ui_v1.use_toolbars: 78 bui.widget( 79 edit=btn, 80 right_widget=bui.get_special_widget('party_button'), 81 ) 82 83 bui.widget( 84 edit=cancel_button, 85 left_widget=cancel_button, 86 right_widget=save_button, 87 ) 88 89 bui.textwidget( 90 parent=self._root_widget, 91 position=(-10, self._height - 50), 92 size=(self._width, 25), 93 text=bui.Lstr(resource=f'{self._r}.titleText'), 94 color=bui.app.ui_v1.title_color, 95 scale=1.05, 96 h_align='center', 97 v_align='center', 98 maxwidth=270, 99 ) 100 101 v = self._height - 115.0 102 103 self._scroll_width = self._width - (205 + 2 * x_inset) 104 105 bui.textwidget( 106 parent=self._root_widget, 107 text=bui.Lstr(resource=f'{self._r}.listNameText'), 108 position=(196 + x_inset, v + 31), 109 maxwidth=150, 110 color=(0.8, 0.8, 0.8, 0.5), 111 size=(0, 0), 112 scale=0.75, 113 h_align='right', 114 v_align='center', 115 ) 116 117 self._text_field = bui.textwidget( 118 parent=self._root_widget, 119 position=(210 + x_inset, v + 7), 120 size=(self._scroll_width - 53, 43), 121 text=self._editcontroller.getname(), 122 h_align='left', 123 v_align='center', 124 max_chars=40, 125 maxwidth=380, 126 autoselect=True, 127 color=(0.9, 0.9, 0.9, 1.0), 128 description=bui.Lstr(resource=f'{self._r}.listNameText'), 129 editable=True, 130 padding=4, 131 on_return_press_call=self._save_press_with_sound, 132 ) 133 bui.widget(edit=cancel_button, down_widget=self._text_field) 134 135 self._list_widgets: list[bui.Widget] = [] 136 137 h = 40 + x_inset 138 v = self._height - 172.0 139 140 b_color = (0.6, 0.53, 0.63) 141 b_textcolor = (0.75, 0.7, 0.8) 142 143 v -= 2.0 144 v += 63 145 146 scl = ( 147 1.03 148 if uiscale is bui.UIScale.SMALL 149 else 1.36 if uiscale is bui.UIScale.MEDIUM else 1.74 150 ) 151 v -= 63.0 * scl 152 153 add_game_button = bui.buttonwidget( 154 parent=self._root_widget, 155 position=(h, v), 156 size=(110, 61.0 * scl), 157 on_activate_call=self._add, 158 on_select_call=bui.Call(self._set_ui_selection, 'add_button'), 159 autoselect=True, 160 button_type='square', 161 color=b_color, 162 textcolor=b_textcolor, 163 text_scale=0.8, 164 label=bui.Lstr(resource=f'{self._r}.addGameText'), 165 ) 166 bui.widget(edit=add_game_button, up_widget=self._text_field) 167 v -= 63.0 * scl 168 169 self._edit_button = edit_game_button = bui.buttonwidget( 170 parent=self._root_widget, 171 position=(h, v), 172 size=(110, 61.0 * scl), 173 on_activate_call=self._edit, 174 on_select_call=bui.Call(self._set_ui_selection, 'editButton'), 175 autoselect=True, 176 button_type='square', 177 color=b_color, 178 textcolor=b_textcolor, 179 text_scale=0.8, 180 label=bui.Lstr(resource=f'{self._r}.editGameText'), 181 ) 182 v -= 63.0 * scl 183 184 remove_game_button = bui.buttonwidget( 185 parent=self._root_widget, 186 position=(h, v), 187 size=(110, 61.0 * scl), 188 text_scale=0.8, 189 on_activate_call=self._remove, 190 autoselect=True, 191 button_type='square', 192 color=b_color, 193 textcolor=b_textcolor, 194 label=bui.Lstr(resource=f'{self._r}.removeGameText'), 195 ) 196 v -= 40 197 h += 9 198 bui.buttonwidget( 199 parent=self._root_widget, 200 position=(h, v), 201 size=(42, 35), 202 on_activate_call=self._move_up, 203 label=bui.charstr(bui.SpecialChar.UP_ARROW), 204 button_type='square', 205 color=b_color, 206 textcolor=b_textcolor, 207 autoselect=True, 208 repeat=True, 209 ) 210 h += 52 211 bui.buttonwidget( 212 parent=self._root_widget, 213 position=(h, v), 214 size=(42, 35), 215 on_activate_call=self._move_down, 216 autoselect=True, 217 button_type='square', 218 color=b_color, 219 textcolor=b_textcolor, 220 label=bui.charstr(bui.SpecialChar.DOWN_ARROW), 221 repeat=True, 222 ) 223 224 v = self._height - 100 225 scroll_height = self._height - 155 226 scrollwidget = bui.scrollwidget( 227 parent=self._root_widget, 228 position=(160 + x_inset, v - scroll_height), 229 highlight=False, 230 on_select_call=bui.Call(self._set_ui_selection, 'gameList'), 231 size=(self._scroll_width, (scroll_height - 15)), 232 ) 233 bui.widget( 234 edit=scrollwidget, 235 left_widget=add_game_button, 236 right_widget=scrollwidget, 237 ) 238 self._columnwidget = bui.columnwidget( 239 parent=scrollwidget, border=2, margin=0 240 ) 241 bui.widget(edit=self._columnwidget, up_widget=self._text_field) 242 243 for button in [add_game_button, edit_game_button, remove_game_button]: 244 bui.widget( 245 edit=button, left_widget=button, right_widget=scrollwidget 246 ) 247 248 self._refresh() 249 250 bui.buttonwidget(edit=cancel_button, on_activate_call=self._cancel) 251 bui.containerwidget( 252 edit=self._root_widget, 253 cancel_button=cancel_button, 254 selected_child=scrollwidget, 255 ) 256 257 bui.buttonwidget(edit=save_button, on_activate_call=self._save_press) 258 bui.containerwidget(edit=self._root_widget, start_button=save_button) 259 260 if prev_selection == 'add_button': 261 bui.containerwidget( 262 edit=self._root_widget, selected_child=add_game_button 263 ) 264 elif prev_selection == 'editButton': 265 bui.containerwidget( 266 edit=self._root_widget, selected_child=edit_game_button 267 ) 268 elif prev_selection == 'gameList': 269 bui.containerwidget( 270 edit=self._root_widget, selected_child=scrollwidget 271 ) 272 273 def _set_ui_selection(self, selection: str) -> None: 274 self._editcontroller.set_edit_ui_selection(selection) 275 276 def _cancel(self) -> None: 277 from bauiv1lib.playlist.customizebrowser import ( 278 PlaylistCustomizeBrowserWindow, 279 ) 280 281 # no-op if our underlying widget is dead or on its way out. 282 if not self._root_widget or self._root_widget.transitioning_out: 283 return 284 285 bui.getsound('powerdown01').play() 286 bui.containerwidget(edit=self._root_widget, transition='out_right') 287 assert bui.app.classic is not None 288 bui.app.ui_v1.set_main_menu_window( 289 PlaylistCustomizeBrowserWindow( 290 transition='in_left', 291 sessiontype=self._editcontroller.get_session_type(), 292 select_playlist=( 293 self._editcontroller.get_existing_playlist_name() 294 ), 295 ).get_root_widget(), 296 from_window=self._root_widget, 297 ) 298 299 def _add(self) -> None: 300 # Store list name then tell the session to perform an add. 301 self._editcontroller.setname( 302 cast(str, bui.textwidget(query=self._text_field)) 303 ) 304 self._editcontroller.add_game_pressed() 305 306 def _edit(self) -> None: 307 # Store list name then tell the session to perform an add. 308 self._editcontroller.setname( 309 cast(str, bui.textwidget(query=self._text_field)) 310 ) 311 self._editcontroller.edit_game_pressed() 312 313 def _save_press(self) -> None: 314 from bauiv1lib.playlist.customizebrowser import ( 315 PlaylistCustomizeBrowserWindow, 316 ) 317 318 # no-op if our underlying widget is dead or on its way out. 319 if not self._root_widget or self._root_widget.transitioning_out: 320 return 321 322 plus = bui.app.plus 323 assert plus is not None 324 325 new_name = cast(str, bui.textwidget(query=self._text_field)) 326 if ( 327 new_name != self._editcontroller.get_existing_playlist_name() 328 and new_name 329 in bui.app.config[ 330 self._editcontroller.get_config_name() + ' Playlists' 331 ] 332 ): 333 bui.screenmessage( 334 bui.Lstr(resource=f'{self._r}.cantSaveAlreadyExistsText') 335 ) 336 bui.getsound('error').play() 337 return 338 if not new_name: 339 bui.getsound('error').play() 340 return 341 if not self._editcontroller.get_playlist(): 342 bui.screenmessage( 343 bui.Lstr(resource=f'{self._r}.cantSaveEmptyListText') 344 ) 345 bui.getsound('error').play() 346 return 347 348 # We couldn't actually replace the default list anyway, but disallow 349 # using its exact name to avoid confusion. 350 if new_name == self._editcontroller.get_default_list_name().evaluate(): 351 bui.screenmessage( 352 bui.Lstr(resource=f'{self._r}.cantOverwriteDefaultText') 353 ) 354 bui.getsound('error').play() 355 return 356 357 # If we had an old one, delete it. 358 if self._editcontroller.get_existing_playlist_name() is not None: 359 plus.add_v1_account_transaction( 360 { 361 'type': 'REMOVE_PLAYLIST', 362 'playlistType': self._editcontroller.get_config_name(), 363 'playlistName': ( 364 self._editcontroller.get_existing_playlist_name() 365 ), 366 } 367 ) 368 369 plus.add_v1_account_transaction( 370 { 371 'type': 'ADD_PLAYLIST', 372 'playlistType': self._editcontroller.get_config_name(), 373 'playlistName': new_name, 374 'playlist': self._editcontroller.get_playlist(), 375 } 376 ) 377 plus.run_v1_account_transactions() 378 379 bui.containerwidget(edit=self._root_widget, transition='out_right') 380 bui.getsound('gunCocking').play() 381 assert bui.app.classic is not None 382 bui.app.ui_v1.set_main_menu_window( 383 PlaylistCustomizeBrowserWindow( 384 transition='in_left', 385 sessiontype=self._editcontroller.get_session_type(), 386 select_playlist=new_name, 387 ).get_root_widget(), 388 from_window=self._root_widget, 389 ) 390 391 def _save_press_with_sound(self) -> None: 392 bui.getsound('swish').play() 393 self._save_press() 394 395 def _select(self, index: int) -> None: 396 self._editcontroller.set_selected_index(index) 397 398 def _refresh(self) -> None: 399 # Need to grab this here as rebuilding the list will 400 # change it otherwise. 401 old_selection_index = self._editcontroller.get_selected_index() 402 403 while self._list_widgets: 404 self._list_widgets.pop().delete() 405 for index, pentry in enumerate(self._editcontroller.get_playlist()): 406 try: 407 cls = bui.getclass(pentry['type'], subclassof=bs.GameActivity) 408 desc = cls.get_settings_display_string(pentry) 409 except Exception: 410 logging.exception('Error in playlist refresh.') 411 desc = "(invalid: '" + pentry['type'] + "')" 412 413 txtw = bui.textwidget( 414 parent=self._columnwidget, 415 size=(self._width - 80, 30), 416 on_select_call=bui.Call(self._select, index), 417 always_highlight=True, 418 color=(0.8, 0.8, 0.8, 1.0), 419 padding=0, 420 maxwidth=self._scroll_width * 0.93, 421 text=desc, 422 on_activate_call=self._edit_button.activate, 423 v_align='center', 424 selectable=True, 425 ) 426 bui.widget(edit=txtw, show_buffer_top=50, show_buffer_bottom=50) 427 428 # Wanna be able to jump up to the text field from the top one. 429 if index == 0: 430 bui.widget(edit=txtw, up_widget=self._text_field) 431 self._list_widgets.append(txtw) 432 if old_selection_index == index: 433 bui.columnwidget( 434 edit=self._columnwidget, 435 selected_child=txtw, 436 visible_child=txtw, 437 ) 438 439 def _move_down(self) -> None: 440 playlist = self._editcontroller.get_playlist() 441 index = self._editcontroller.get_selected_index() 442 if index >= len(playlist) - 1: 443 return 444 tmp = playlist[index] 445 playlist[index] = playlist[index + 1] 446 playlist[index + 1] = tmp 447 index += 1 448 self._editcontroller.set_playlist(playlist) 449 self._editcontroller.set_selected_index(index) 450 self._refresh() 451 452 def _move_up(self) -> None: 453 playlist = self._editcontroller.get_playlist() 454 index = self._editcontroller.get_selected_index() 455 if index < 1: 456 return 457 tmp = playlist[index] 458 playlist[index] = playlist[index - 1] 459 playlist[index - 1] = tmp 460 index -= 1 461 self._editcontroller.set_playlist(playlist) 462 self._editcontroller.set_selected_index(index) 463 self._refresh() 464 465 def _remove(self) -> None: 466 playlist = self._editcontroller.get_playlist() 467 index = self._editcontroller.get_selected_index() 468 if not playlist: 469 return 470 del playlist[index] 471 if index >= len(playlist): 472 index = len(playlist) - 1 473 self._editcontroller.set_playlist(playlist) 474 self._editcontroller.set_selected_index(index) 475 bui.getsound('shieldDown').play() 476 self._refresh()
class
PlaylistEditWindow(bauiv1._uitypes.Window):
18class PlaylistEditWindow(bui.Window): 19 """Window for editing an individual game playlist.""" 20 21 def __init__( 22 self, 23 editcontroller: PlaylistEditController, 24 transition: str = 'in_right', 25 ): 26 # pylint: disable=too-many-statements 27 # pylint: disable=too-many-locals 28 prev_selection: str | None 29 self._editcontroller = editcontroller 30 self._r = 'editGameListWindow' 31 prev_selection = self._editcontroller.get_edit_ui_selection() 32 33 assert bui.app.classic is not None 34 uiscale = bui.app.ui_v1.uiscale 35 self._width = 870 if uiscale is bui.UIScale.SMALL else 670 36 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 37 self._height = ( 38 400 39 if uiscale is bui.UIScale.SMALL 40 else 470 if uiscale is bui.UIScale.MEDIUM else 540 41 ) 42 43 top_extra = 20 if uiscale is bui.UIScale.SMALL else 0 44 super().__init__( 45 root_widget=bui.containerwidget( 46 size=(self._width, self._height + top_extra), 47 transition=transition, 48 scale=( 49 2.0 50 if uiscale is bui.UIScale.SMALL 51 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 52 ), 53 stack_offset=( 54 (0, -16) if uiscale is bui.UIScale.SMALL else (0, 0) 55 ), 56 ) 57 ) 58 cancel_button = bui.buttonwidget( 59 parent=self._root_widget, 60 position=(35 + x_inset, self._height - 60), 61 scale=0.8, 62 size=(175, 60), 63 autoselect=True, 64 label=bui.Lstr(resource='cancelText'), 65 text_scale=1.2, 66 ) 67 save_button = btn = bui.buttonwidget( 68 parent=self._root_widget, 69 position=(self._width - (195 + x_inset), self._height - 60), 70 scale=0.8, 71 size=(190, 60), 72 autoselect=True, 73 left_widget=cancel_button, 74 label=bui.Lstr(resource='saveText'), 75 text_scale=1.2, 76 ) 77 78 if bui.app.ui_v1.use_toolbars: 79 bui.widget( 80 edit=btn, 81 right_widget=bui.get_special_widget('party_button'), 82 ) 83 84 bui.widget( 85 edit=cancel_button, 86 left_widget=cancel_button, 87 right_widget=save_button, 88 ) 89 90 bui.textwidget( 91 parent=self._root_widget, 92 position=(-10, self._height - 50), 93 size=(self._width, 25), 94 text=bui.Lstr(resource=f'{self._r}.titleText'), 95 color=bui.app.ui_v1.title_color, 96 scale=1.05, 97 h_align='center', 98 v_align='center', 99 maxwidth=270, 100 ) 101 102 v = self._height - 115.0 103 104 self._scroll_width = self._width - (205 + 2 * x_inset) 105 106 bui.textwidget( 107 parent=self._root_widget, 108 text=bui.Lstr(resource=f'{self._r}.listNameText'), 109 position=(196 + x_inset, v + 31), 110 maxwidth=150, 111 color=(0.8, 0.8, 0.8, 0.5), 112 size=(0, 0), 113 scale=0.75, 114 h_align='right', 115 v_align='center', 116 ) 117 118 self._text_field = bui.textwidget( 119 parent=self._root_widget, 120 position=(210 + x_inset, v + 7), 121 size=(self._scroll_width - 53, 43), 122 text=self._editcontroller.getname(), 123 h_align='left', 124 v_align='center', 125 max_chars=40, 126 maxwidth=380, 127 autoselect=True, 128 color=(0.9, 0.9, 0.9, 1.0), 129 description=bui.Lstr(resource=f'{self._r}.listNameText'), 130 editable=True, 131 padding=4, 132 on_return_press_call=self._save_press_with_sound, 133 ) 134 bui.widget(edit=cancel_button, down_widget=self._text_field) 135 136 self._list_widgets: list[bui.Widget] = [] 137 138 h = 40 + x_inset 139 v = self._height - 172.0 140 141 b_color = (0.6, 0.53, 0.63) 142 b_textcolor = (0.75, 0.7, 0.8) 143 144 v -= 2.0 145 v += 63 146 147 scl = ( 148 1.03 149 if uiscale is bui.UIScale.SMALL 150 else 1.36 if uiscale is bui.UIScale.MEDIUM else 1.74 151 ) 152 v -= 63.0 * scl 153 154 add_game_button = bui.buttonwidget( 155 parent=self._root_widget, 156 position=(h, v), 157 size=(110, 61.0 * scl), 158 on_activate_call=self._add, 159 on_select_call=bui.Call(self._set_ui_selection, 'add_button'), 160 autoselect=True, 161 button_type='square', 162 color=b_color, 163 textcolor=b_textcolor, 164 text_scale=0.8, 165 label=bui.Lstr(resource=f'{self._r}.addGameText'), 166 ) 167 bui.widget(edit=add_game_button, up_widget=self._text_field) 168 v -= 63.0 * scl 169 170 self._edit_button = edit_game_button = bui.buttonwidget( 171 parent=self._root_widget, 172 position=(h, v), 173 size=(110, 61.0 * scl), 174 on_activate_call=self._edit, 175 on_select_call=bui.Call(self._set_ui_selection, 'editButton'), 176 autoselect=True, 177 button_type='square', 178 color=b_color, 179 textcolor=b_textcolor, 180 text_scale=0.8, 181 label=bui.Lstr(resource=f'{self._r}.editGameText'), 182 ) 183 v -= 63.0 * scl 184 185 remove_game_button = bui.buttonwidget( 186 parent=self._root_widget, 187 position=(h, v), 188 size=(110, 61.0 * scl), 189 text_scale=0.8, 190 on_activate_call=self._remove, 191 autoselect=True, 192 button_type='square', 193 color=b_color, 194 textcolor=b_textcolor, 195 label=bui.Lstr(resource=f'{self._r}.removeGameText'), 196 ) 197 v -= 40 198 h += 9 199 bui.buttonwidget( 200 parent=self._root_widget, 201 position=(h, v), 202 size=(42, 35), 203 on_activate_call=self._move_up, 204 label=bui.charstr(bui.SpecialChar.UP_ARROW), 205 button_type='square', 206 color=b_color, 207 textcolor=b_textcolor, 208 autoselect=True, 209 repeat=True, 210 ) 211 h += 52 212 bui.buttonwidget( 213 parent=self._root_widget, 214 position=(h, v), 215 size=(42, 35), 216 on_activate_call=self._move_down, 217 autoselect=True, 218 button_type='square', 219 color=b_color, 220 textcolor=b_textcolor, 221 label=bui.charstr(bui.SpecialChar.DOWN_ARROW), 222 repeat=True, 223 ) 224 225 v = self._height - 100 226 scroll_height = self._height - 155 227 scrollwidget = bui.scrollwidget( 228 parent=self._root_widget, 229 position=(160 + x_inset, v - scroll_height), 230 highlight=False, 231 on_select_call=bui.Call(self._set_ui_selection, 'gameList'), 232 size=(self._scroll_width, (scroll_height - 15)), 233 ) 234 bui.widget( 235 edit=scrollwidget, 236 left_widget=add_game_button, 237 right_widget=scrollwidget, 238 ) 239 self._columnwidget = bui.columnwidget( 240 parent=scrollwidget, border=2, margin=0 241 ) 242 bui.widget(edit=self._columnwidget, up_widget=self._text_field) 243 244 for button in [add_game_button, edit_game_button, remove_game_button]: 245 bui.widget( 246 edit=button, left_widget=button, right_widget=scrollwidget 247 ) 248 249 self._refresh() 250 251 bui.buttonwidget(edit=cancel_button, on_activate_call=self._cancel) 252 bui.containerwidget( 253 edit=self._root_widget, 254 cancel_button=cancel_button, 255 selected_child=scrollwidget, 256 ) 257 258 bui.buttonwidget(edit=save_button, on_activate_call=self._save_press) 259 bui.containerwidget(edit=self._root_widget, start_button=save_button) 260 261 if prev_selection == 'add_button': 262 bui.containerwidget( 263 edit=self._root_widget, selected_child=add_game_button 264 ) 265 elif prev_selection == 'editButton': 266 bui.containerwidget( 267 edit=self._root_widget, selected_child=edit_game_button 268 ) 269 elif prev_selection == 'gameList': 270 bui.containerwidget( 271 edit=self._root_widget, selected_child=scrollwidget 272 ) 273 274 def _set_ui_selection(self, selection: str) -> None: 275 self._editcontroller.set_edit_ui_selection(selection) 276 277 def _cancel(self) -> None: 278 from bauiv1lib.playlist.customizebrowser import ( 279 PlaylistCustomizeBrowserWindow, 280 ) 281 282 # no-op if our underlying widget is dead or on its way out. 283 if not self._root_widget or self._root_widget.transitioning_out: 284 return 285 286 bui.getsound('powerdown01').play() 287 bui.containerwidget(edit=self._root_widget, transition='out_right') 288 assert bui.app.classic is not None 289 bui.app.ui_v1.set_main_menu_window( 290 PlaylistCustomizeBrowserWindow( 291 transition='in_left', 292 sessiontype=self._editcontroller.get_session_type(), 293 select_playlist=( 294 self._editcontroller.get_existing_playlist_name() 295 ), 296 ).get_root_widget(), 297 from_window=self._root_widget, 298 ) 299 300 def _add(self) -> None: 301 # Store list name then tell the session to perform an add. 302 self._editcontroller.setname( 303 cast(str, bui.textwidget(query=self._text_field)) 304 ) 305 self._editcontroller.add_game_pressed() 306 307 def _edit(self) -> None: 308 # Store list name then tell the session to perform an add. 309 self._editcontroller.setname( 310 cast(str, bui.textwidget(query=self._text_field)) 311 ) 312 self._editcontroller.edit_game_pressed() 313 314 def _save_press(self) -> None: 315 from bauiv1lib.playlist.customizebrowser import ( 316 PlaylistCustomizeBrowserWindow, 317 ) 318 319 # no-op if our underlying widget is dead or on its way out. 320 if not self._root_widget or self._root_widget.transitioning_out: 321 return 322 323 plus = bui.app.plus 324 assert plus is not None 325 326 new_name = cast(str, bui.textwidget(query=self._text_field)) 327 if ( 328 new_name != self._editcontroller.get_existing_playlist_name() 329 and new_name 330 in bui.app.config[ 331 self._editcontroller.get_config_name() + ' Playlists' 332 ] 333 ): 334 bui.screenmessage( 335 bui.Lstr(resource=f'{self._r}.cantSaveAlreadyExistsText') 336 ) 337 bui.getsound('error').play() 338 return 339 if not new_name: 340 bui.getsound('error').play() 341 return 342 if not self._editcontroller.get_playlist(): 343 bui.screenmessage( 344 bui.Lstr(resource=f'{self._r}.cantSaveEmptyListText') 345 ) 346 bui.getsound('error').play() 347 return 348 349 # We couldn't actually replace the default list anyway, but disallow 350 # using its exact name to avoid confusion. 351 if new_name == self._editcontroller.get_default_list_name().evaluate(): 352 bui.screenmessage( 353 bui.Lstr(resource=f'{self._r}.cantOverwriteDefaultText') 354 ) 355 bui.getsound('error').play() 356 return 357 358 # If we had an old one, delete it. 359 if self._editcontroller.get_existing_playlist_name() is not None: 360 plus.add_v1_account_transaction( 361 { 362 'type': 'REMOVE_PLAYLIST', 363 'playlistType': self._editcontroller.get_config_name(), 364 'playlistName': ( 365 self._editcontroller.get_existing_playlist_name() 366 ), 367 } 368 ) 369 370 plus.add_v1_account_transaction( 371 { 372 'type': 'ADD_PLAYLIST', 373 'playlistType': self._editcontroller.get_config_name(), 374 'playlistName': new_name, 375 'playlist': self._editcontroller.get_playlist(), 376 } 377 ) 378 plus.run_v1_account_transactions() 379 380 bui.containerwidget(edit=self._root_widget, transition='out_right') 381 bui.getsound('gunCocking').play() 382 assert bui.app.classic is not None 383 bui.app.ui_v1.set_main_menu_window( 384 PlaylistCustomizeBrowserWindow( 385 transition='in_left', 386 sessiontype=self._editcontroller.get_session_type(), 387 select_playlist=new_name, 388 ).get_root_widget(), 389 from_window=self._root_widget, 390 ) 391 392 def _save_press_with_sound(self) -> None: 393 bui.getsound('swish').play() 394 self._save_press() 395 396 def _select(self, index: int) -> None: 397 self._editcontroller.set_selected_index(index) 398 399 def _refresh(self) -> None: 400 # Need to grab this here as rebuilding the list will 401 # change it otherwise. 402 old_selection_index = self._editcontroller.get_selected_index() 403 404 while self._list_widgets: 405 self._list_widgets.pop().delete() 406 for index, pentry in enumerate(self._editcontroller.get_playlist()): 407 try: 408 cls = bui.getclass(pentry['type'], subclassof=bs.GameActivity) 409 desc = cls.get_settings_display_string(pentry) 410 except Exception: 411 logging.exception('Error in playlist refresh.') 412 desc = "(invalid: '" + pentry['type'] + "')" 413 414 txtw = bui.textwidget( 415 parent=self._columnwidget, 416 size=(self._width - 80, 30), 417 on_select_call=bui.Call(self._select, index), 418 always_highlight=True, 419 color=(0.8, 0.8, 0.8, 1.0), 420 padding=0, 421 maxwidth=self._scroll_width * 0.93, 422 text=desc, 423 on_activate_call=self._edit_button.activate, 424 v_align='center', 425 selectable=True, 426 ) 427 bui.widget(edit=txtw, show_buffer_top=50, show_buffer_bottom=50) 428 429 # Wanna be able to jump up to the text field from the top one. 430 if index == 0: 431 bui.widget(edit=txtw, up_widget=self._text_field) 432 self._list_widgets.append(txtw) 433 if old_selection_index == index: 434 bui.columnwidget( 435 edit=self._columnwidget, 436 selected_child=txtw, 437 visible_child=txtw, 438 ) 439 440 def _move_down(self) -> None: 441 playlist = self._editcontroller.get_playlist() 442 index = self._editcontroller.get_selected_index() 443 if index >= len(playlist) - 1: 444 return 445 tmp = playlist[index] 446 playlist[index] = playlist[index + 1] 447 playlist[index + 1] = tmp 448 index += 1 449 self._editcontroller.set_playlist(playlist) 450 self._editcontroller.set_selected_index(index) 451 self._refresh() 452 453 def _move_up(self) -> None: 454 playlist = self._editcontroller.get_playlist() 455 index = self._editcontroller.get_selected_index() 456 if index < 1: 457 return 458 tmp = playlist[index] 459 playlist[index] = playlist[index - 1] 460 playlist[index - 1] = tmp 461 index -= 1 462 self._editcontroller.set_playlist(playlist) 463 self._editcontroller.set_selected_index(index) 464 self._refresh() 465 466 def _remove(self) -> None: 467 playlist = self._editcontroller.get_playlist() 468 index = self._editcontroller.get_selected_index() 469 if not playlist: 470 return 471 del playlist[index] 472 if index >= len(playlist): 473 index = len(playlist) - 1 474 self._editcontroller.set_playlist(playlist) 475 self._editcontroller.set_selected_index(index) 476 bui.getsound('shieldDown').play() 477 self._refresh()
Window for editing an individual game playlist.
PlaylistEditWindow( editcontroller: bauiv1lib.playlist.editcontroller.PlaylistEditController, transition: str = 'in_right')
21 def __init__( 22 self, 23 editcontroller: PlaylistEditController, 24 transition: str = 'in_right', 25 ): 26 # pylint: disable=too-many-statements 27 # pylint: disable=too-many-locals 28 prev_selection: str | None 29 self._editcontroller = editcontroller 30 self._r = 'editGameListWindow' 31 prev_selection = self._editcontroller.get_edit_ui_selection() 32 33 assert bui.app.classic is not None 34 uiscale = bui.app.ui_v1.uiscale 35 self._width = 870 if uiscale is bui.UIScale.SMALL else 670 36 x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 37 self._height = ( 38 400 39 if uiscale is bui.UIScale.SMALL 40 else 470 if uiscale is bui.UIScale.MEDIUM else 540 41 ) 42 43 top_extra = 20 if uiscale is bui.UIScale.SMALL else 0 44 super().__init__( 45 root_widget=bui.containerwidget( 46 size=(self._width, self._height + top_extra), 47 transition=transition, 48 scale=( 49 2.0 50 if uiscale is bui.UIScale.SMALL 51 else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0 52 ), 53 stack_offset=( 54 (0, -16) if uiscale is bui.UIScale.SMALL else (0, 0) 55 ), 56 ) 57 ) 58 cancel_button = bui.buttonwidget( 59 parent=self._root_widget, 60 position=(35 + x_inset, self._height - 60), 61 scale=0.8, 62 size=(175, 60), 63 autoselect=True, 64 label=bui.Lstr(resource='cancelText'), 65 text_scale=1.2, 66 ) 67 save_button = btn = bui.buttonwidget( 68 parent=self._root_widget, 69 position=(self._width - (195 + x_inset), self._height - 60), 70 scale=0.8, 71 size=(190, 60), 72 autoselect=True, 73 left_widget=cancel_button, 74 label=bui.Lstr(resource='saveText'), 75 text_scale=1.2, 76 ) 77 78 if bui.app.ui_v1.use_toolbars: 79 bui.widget( 80 edit=btn, 81 right_widget=bui.get_special_widget('party_button'), 82 ) 83 84 bui.widget( 85 edit=cancel_button, 86 left_widget=cancel_button, 87 right_widget=save_button, 88 ) 89 90 bui.textwidget( 91 parent=self._root_widget, 92 position=(-10, self._height - 50), 93 size=(self._width, 25), 94 text=bui.Lstr(resource=f'{self._r}.titleText'), 95 color=bui.app.ui_v1.title_color, 96 scale=1.05, 97 h_align='center', 98 v_align='center', 99 maxwidth=270, 100 ) 101 102 v = self._height - 115.0 103 104 self._scroll_width = self._width - (205 + 2 * x_inset) 105 106 bui.textwidget( 107 parent=self._root_widget, 108 text=bui.Lstr(resource=f'{self._r}.listNameText'), 109 position=(196 + x_inset, v + 31), 110 maxwidth=150, 111 color=(0.8, 0.8, 0.8, 0.5), 112 size=(0, 0), 113 scale=0.75, 114 h_align='right', 115 v_align='center', 116 ) 117 118 self._text_field = bui.textwidget( 119 parent=self._root_widget, 120 position=(210 + x_inset, v + 7), 121 size=(self._scroll_width - 53, 43), 122 text=self._editcontroller.getname(), 123 h_align='left', 124 v_align='center', 125 max_chars=40, 126 maxwidth=380, 127 autoselect=True, 128 color=(0.9, 0.9, 0.9, 1.0), 129 description=bui.Lstr(resource=f'{self._r}.listNameText'), 130 editable=True, 131 padding=4, 132 on_return_press_call=self._save_press_with_sound, 133 ) 134 bui.widget(edit=cancel_button, down_widget=self._text_field) 135 136 self._list_widgets: list[bui.Widget] = [] 137 138 h = 40 + x_inset 139 v = self._height - 172.0 140 141 b_color = (0.6, 0.53, 0.63) 142 b_textcolor = (0.75, 0.7, 0.8) 143 144 v -= 2.0 145 v += 63 146 147 scl = ( 148 1.03 149 if uiscale is bui.UIScale.SMALL 150 else 1.36 if uiscale is bui.UIScale.MEDIUM else 1.74 151 ) 152 v -= 63.0 * scl 153 154 add_game_button = bui.buttonwidget( 155 parent=self._root_widget, 156 position=(h, v), 157 size=(110, 61.0 * scl), 158 on_activate_call=self._add, 159 on_select_call=bui.Call(self._set_ui_selection, 'add_button'), 160 autoselect=True, 161 button_type='square', 162 color=b_color, 163 textcolor=b_textcolor, 164 text_scale=0.8, 165 label=bui.Lstr(resource=f'{self._r}.addGameText'), 166 ) 167 bui.widget(edit=add_game_button, up_widget=self._text_field) 168 v -= 63.0 * scl 169 170 self._edit_button = edit_game_button = bui.buttonwidget( 171 parent=self._root_widget, 172 position=(h, v), 173 size=(110, 61.0 * scl), 174 on_activate_call=self._edit, 175 on_select_call=bui.Call(self._set_ui_selection, 'editButton'), 176 autoselect=True, 177 button_type='square', 178 color=b_color, 179 textcolor=b_textcolor, 180 text_scale=0.8, 181 label=bui.Lstr(resource=f'{self._r}.editGameText'), 182 ) 183 v -= 63.0 * scl 184 185 remove_game_button = bui.buttonwidget( 186 parent=self._root_widget, 187 position=(h, v), 188 size=(110, 61.0 * scl), 189 text_scale=0.8, 190 on_activate_call=self._remove, 191 autoselect=True, 192 button_type='square', 193 color=b_color, 194 textcolor=b_textcolor, 195 label=bui.Lstr(resource=f'{self._r}.removeGameText'), 196 ) 197 v -= 40 198 h += 9 199 bui.buttonwidget( 200 parent=self._root_widget, 201 position=(h, v), 202 size=(42, 35), 203 on_activate_call=self._move_up, 204 label=bui.charstr(bui.SpecialChar.UP_ARROW), 205 button_type='square', 206 color=b_color, 207 textcolor=b_textcolor, 208 autoselect=True, 209 repeat=True, 210 ) 211 h += 52 212 bui.buttonwidget( 213 parent=self._root_widget, 214 position=(h, v), 215 size=(42, 35), 216 on_activate_call=self._move_down, 217 autoselect=True, 218 button_type='square', 219 color=b_color, 220 textcolor=b_textcolor, 221 label=bui.charstr(bui.SpecialChar.DOWN_ARROW), 222 repeat=True, 223 ) 224 225 v = self._height - 100 226 scroll_height = self._height - 155 227 scrollwidget = bui.scrollwidget( 228 parent=self._root_widget, 229 position=(160 + x_inset, v - scroll_height), 230 highlight=False, 231 on_select_call=bui.Call(self._set_ui_selection, 'gameList'), 232 size=(self._scroll_width, (scroll_height - 15)), 233 ) 234 bui.widget( 235 edit=scrollwidget, 236 left_widget=add_game_button, 237 right_widget=scrollwidget, 238 ) 239 self._columnwidget = bui.columnwidget( 240 parent=scrollwidget, border=2, margin=0 241 ) 242 bui.widget(edit=self._columnwidget, up_widget=self._text_field) 243 244 for button in [add_game_button, edit_game_button, remove_game_button]: 245 bui.widget( 246 edit=button, left_widget=button, right_widget=scrollwidget 247 ) 248 249 self._refresh() 250 251 bui.buttonwidget(edit=cancel_button, on_activate_call=self._cancel) 252 bui.containerwidget( 253 edit=self._root_widget, 254 cancel_button=cancel_button, 255 selected_child=scrollwidget, 256 ) 257 258 bui.buttonwidget(edit=save_button, on_activate_call=self._save_press) 259 bui.containerwidget(edit=self._root_widget, start_button=save_button) 260 261 if prev_selection == 'add_button': 262 bui.containerwidget( 263 edit=self._root_widget, selected_child=add_game_button 264 ) 265 elif prev_selection == 'editButton': 266 bui.containerwidget( 267 edit=self._root_widget, selected_child=edit_game_button 268 ) 269 elif prev_selection == 'gameList': 270 bui.containerwidget( 271 edit=self._root_widget, selected_child=scrollwidget 272 )
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget