bauiv1lib.playlist.editcontroller
Defines a controller for wrangling playlist edit UIs.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Defines a controller for wrangling playlist edit UIs.""" 4 5from __future__ import annotations 6 7import copy 8from typing import TYPE_CHECKING 9 10import bascenev1 as bs 11import bauiv1 as bui 12 13if TYPE_CHECKING: 14 from typing import Any, Callable 15 16 17class PlaylistEditController: 18 """Coordinates various UIs involved in playlist editing.""" 19 20 def __init__( 21 self, 22 sessiontype: type[bs.Session], 23 from_window: bui.MainWindow, 24 existing_playlist_name: str | None = None, 25 playlist: list[dict[str, Any]] | None = None, 26 playlist_name: str | None = None, 27 ): 28 from bascenev1 import filter_playlist 29 from bauiv1lib.playlist import PlaylistTypeVars 30 from bauiv1lib.playlist.edit import PlaylistEditWindow 31 32 appconfig = bui.app.config 33 34 # Since we may be showing our map list momentarily, 35 # lets go ahead and preload all map preview textures. 36 if bui.app.classic is not None: 37 bui.app.classic.preload_map_preview_media() 38 39 self._sessiontype = sessiontype 40 41 self._editing_game = False 42 self._editing_game_type: type[bs.GameActivity] | None = None 43 self._pvars = PlaylistTypeVars(sessiontype) 44 self._existing_playlist_name = existing_playlist_name 45 self._config_name_full = self._pvars.config_name + ' Playlists' 46 47 self._pre_game_add_state: bui.MainWindowState | None = None 48 self._pre_game_edit_state: bui.MainWindowState | None = None 49 50 # Make sure config exists. 51 if self._config_name_full not in appconfig: 52 appconfig[self._config_name_full] = {} 53 54 self._selected_index = 0 55 if existing_playlist_name: 56 self._name = existing_playlist_name 57 58 # Filter out invalid games. 59 self._playlist = filter_playlist( 60 appconfig[self._pvars.config_name + ' Playlists'][ 61 existing_playlist_name 62 ], 63 sessiontype=sessiontype, 64 remove_unowned=False, 65 name=existing_playlist_name, 66 ) 67 self._edit_ui_selection = None 68 else: 69 if playlist is not None: 70 self._playlist = playlist 71 else: 72 self._playlist = [] 73 if playlist_name is not None: 74 self._name = playlist_name 75 else: 76 # Find a good unused name. 77 i = 1 78 while True: 79 self._name = ( 80 self._pvars.default_new_list_name.evaluate() 81 + ((' ' + str(i)) if i > 1 else '') 82 ) 83 if ( 84 self._name 85 not in appconfig[self._pvars.config_name + ' Playlists'] 86 ): 87 break 88 i += 1 89 90 # Also we want it to start with 'add' highlighted since its empty 91 # and that's all they can do. 92 self._edit_ui_selection = 'add_button' 93 94 editwindow = PlaylistEditWindow(editcontroller=self) 95 from_window.main_window_replace(editwindow) 96 97 # Once we've set our start window, store the back state. We'll 98 # skip back to there once we're fully done. 99 self._back_state = editwindow.main_window_back_state 100 101 def get_config_name(self) -> str: 102 """(internal)""" 103 return self._pvars.config_name 104 105 def get_existing_playlist_name(self) -> str | None: 106 """(internal)""" 107 return self._existing_playlist_name 108 109 def get_edit_ui_selection(self) -> str | None: 110 """(internal)""" 111 return self._edit_ui_selection 112 113 def set_edit_ui_selection(self, selection: str) -> None: 114 """(internal)""" 115 self._edit_ui_selection = selection 116 117 def getname(self) -> str: 118 """(internal)""" 119 return self._name 120 121 def setname(self, name: str) -> None: 122 """(internal)""" 123 self._name = name 124 125 def get_playlist(self) -> list[dict[str, Any]]: 126 """Return the current state of the edited playlist.""" 127 return copy.deepcopy(self._playlist) 128 129 def set_playlist(self, playlist: list[dict[str, Any]]) -> None: 130 """Set the playlist contents.""" 131 self._playlist = copy.deepcopy(playlist) 132 133 def get_session_type(self) -> type[bs.Session]: 134 """Return the bascenev1.Session type for this edit-session.""" 135 return self._sessiontype 136 137 def get_selected_index(self) -> int: 138 """Return the index of the selected playlist.""" 139 return self._selected_index 140 141 def get_default_list_name(self) -> bui.Lstr: 142 """(internal)""" 143 return self._pvars.default_list_name 144 145 def set_selected_index(self, index: int) -> None: 146 """Sets the selected playlist index.""" 147 self._selected_index = index 148 149 def add_game_pressed(self, from_window: bui.MainWindow) -> None: 150 """(internal)""" 151 from bauiv1lib.playlist.addgame import PlaylistAddGameWindow 152 153 # assert bui.app.classic is not None 154 155 # No op if we're not in control. 156 if not from_window.main_window_has_control(): 157 return 158 159 addwindow = PlaylistAddGameWindow(editcontroller=self) 160 from_window.main_window_replace(addwindow) 161 162 # Once we're there, store the back state. We'll use that to jump 163 # back to our current location once the edit is done. 164 assert self._pre_game_add_state is None 165 self._pre_game_add_state = addwindow.main_window_back_state 166 167 def edit_game_pressed(self, from_window: bui.MainWindow) -> None: 168 """Should be called by supplemental UIs when a game is to be edited.""" 169 170 if not self._playlist: 171 return 172 173 self._show_edit_ui( 174 gametype=bui.getclass( 175 self._playlist[self._selected_index]['type'], 176 subclassof=bs.GameActivity, 177 ), 178 settings=self._playlist[self._selected_index], 179 from_window=from_window, 180 ) 181 182 def _show_edit_ui( 183 self, 184 gametype: type[bs.GameActivity], 185 settings: dict[str, Any] | None, 186 from_window: bui.MainWindow, 187 ) -> None: 188 # pylint: disable=cyclic-import 189 from bauiv1lib.playlist.editgame import PlaylistEditGameWindow 190 191 if not from_window.main_window_has_control(): 192 return 193 194 self._editing_game = settings is not None 195 self._editing_game_type = gametype 196 assert self._sessiontype is not None 197 198 # Jump into an edit window. 199 editwindow = PlaylistEditGameWindow( 200 gametype, 201 self._sessiontype, 202 copy.deepcopy(settings), 203 completion_call=self._edit_game_done, 204 ) 205 from_window.main_window_replace(editwindow) 206 207 # Once we're there, store the back state. We'll use that to jump 208 # back to our current location once the edit is done. 209 assert self._pre_game_edit_state is None 210 self._pre_game_edit_state = editwindow.main_window_back_state 211 212 def add_game_type_selected( 213 self, gametype: type[bs.GameActivity], from_window: bui.MainWindow 214 ) -> None: 215 """(internal)""" 216 self._show_edit_ui( 217 gametype=gametype, settings=None, from_window=from_window 218 ) 219 220 def _edit_game_done( 221 self, config: dict[str, Any] | None, from_window: bui.MainWindow 222 ) -> None: 223 224 # No-op if provided window isn't in charge. 225 if not from_window.main_window_has_control(): 226 return 227 228 assert bui.app.classic is not None 229 if config is None: 230 bui.getsound('powerdown01').play() 231 else: 232 # Make sure type is in there. 233 assert self._editing_game_type is not None 234 config['type'] = bui.get_type_name(self._editing_game_type) 235 236 if self._editing_game: 237 self._playlist[self._selected_index] = copy.deepcopy(config) 238 else: 239 # Add a new entry to the playlist. 240 insert_index = min( 241 len(self._playlist), self._selected_index + 1 242 ) 243 self._playlist.insert(insert_index, copy.deepcopy(config)) 244 self._selected_index = insert_index 245 246 bui.getsound('gunCocking').play() 247 248 # If we're adding, jump to before the add started. 249 # Otherwise jump to before the edit started. 250 assert ( 251 self._pre_game_edit_state is not None 252 or self._pre_game_add_state is not None 253 ) 254 if self._pre_game_add_state is not None: 255 from_window.main_window_back_state = self._pre_game_add_state 256 elif self._pre_game_edit_state is not None: 257 from_window.main_window_back_state = self._pre_game_edit_state 258 from_window.main_window_back() 259 self._pre_game_edit_state = None 260 self._pre_game_add_state = None
class
PlaylistEditController:
18class PlaylistEditController: 19 """Coordinates various UIs involved in playlist editing.""" 20 21 def __init__( 22 self, 23 sessiontype: type[bs.Session], 24 from_window: bui.MainWindow, 25 existing_playlist_name: str | None = None, 26 playlist: list[dict[str, Any]] | None = None, 27 playlist_name: str | None = None, 28 ): 29 from bascenev1 import filter_playlist 30 from bauiv1lib.playlist import PlaylistTypeVars 31 from bauiv1lib.playlist.edit import PlaylistEditWindow 32 33 appconfig = bui.app.config 34 35 # Since we may be showing our map list momentarily, 36 # lets go ahead and preload all map preview textures. 37 if bui.app.classic is not None: 38 bui.app.classic.preload_map_preview_media() 39 40 self._sessiontype = sessiontype 41 42 self._editing_game = False 43 self._editing_game_type: type[bs.GameActivity] | None = None 44 self._pvars = PlaylistTypeVars(sessiontype) 45 self._existing_playlist_name = existing_playlist_name 46 self._config_name_full = self._pvars.config_name + ' Playlists' 47 48 self._pre_game_add_state: bui.MainWindowState | None = None 49 self._pre_game_edit_state: bui.MainWindowState | None = None 50 51 # Make sure config exists. 52 if self._config_name_full not in appconfig: 53 appconfig[self._config_name_full] = {} 54 55 self._selected_index = 0 56 if existing_playlist_name: 57 self._name = existing_playlist_name 58 59 # Filter out invalid games. 60 self._playlist = filter_playlist( 61 appconfig[self._pvars.config_name + ' Playlists'][ 62 existing_playlist_name 63 ], 64 sessiontype=sessiontype, 65 remove_unowned=False, 66 name=existing_playlist_name, 67 ) 68 self._edit_ui_selection = None 69 else: 70 if playlist is not None: 71 self._playlist = playlist 72 else: 73 self._playlist = [] 74 if playlist_name is not None: 75 self._name = playlist_name 76 else: 77 # Find a good unused name. 78 i = 1 79 while True: 80 self._name = ( 81 self._pvars.default_new_list_name.evaluate() 82 + ((' ' + str(i)) if i > 1 else '') 83 ) 84 if ( 85 self._name 86 not in appconfig[self._pvars.config_name + ' Playlists'] 87 ): 88 break 89 i += 1 90 91 # Also we want it to start with 'add' highlighted since its empty 92 # and that's all they can do. 93 self._edit_ui_selection = 'add_button' 94 95 editwindow = PlaylistEditWindow(editcontroller=self) 96 from_window.main_window_replace(editwindow) 97 98 # Once we've set our start window, store the back state. We'll 99 # skip back to there once we're fully done. 100 self._back_state = editwindow.main_window_back_state 101 102 def get_config_name(self) -> str: 103 """(internal)""" 104 return self._pvars.config_name 105 106 def get_existing_playlist_name(self) -> str | None: 107 """(internal)""" 108 return self._existing_playlist_name 109 110 def get_edit_ui_selection(self) -> str | None: 111 """(internal)""" 112 return self._edit_ui_selection 113 114 def set_edit_ui_selection(self, selection: str) -> None: 115 """(internal)""" 116 self._edit_ui_selection = selection 117 118 def getname(self) -> str: 119 """(internal)""" 120 return self._name 121 122 def setname(self, name: str) -> None: 123 """(internal)""" 124 self._name = name 125 126 def get_playlist(self) -> list[dict[str, Any]]: 127 """Return the current state of the edited playlist.""" 128 return copy.deepcopy(self._playlist) 129 130 def set_playlist(self, playlist: list[dict[str, Any]]) -> None: 131 """Set the playlist contents.""" 132 self._playlist = copy.deepcopy(playlist) 133 134 def get_session_type(self) -> type[bs.Session]: 135 """Return the bascenev1.Session type for this edit-session.""" 136 return self._sessiontype 137 138 def get_selected_index(self) -> int: 139 """Return the index of the selected playlist.""" 140 return self._selected_index 141 142 def get_default_list_name(self) -> bui.Lstr: 143 """(internal)""" 144 return self._pvars.default_list_name 145 146 def set_selected_index(self, index: int) -> None: 147 """Sets the selected playlist index.""" 148 self._selected_index = index 149 150 def add_game_pressed(self, from_window: bui.MainWindow) -> None: 151 """(internal)""" 152 from bauiv1lib.playlist.addgame import PlaylistAddGameWindow 153 154 # assert bui.app.classic is not None 155 156 # No op if we're not in control. 157 if not from_window.main_window_has_control(): 158 return 159 160 addwindow = PlaylistAddGameWindow(editcontroller=self) 161 from_window.main_window_replace(addwindow) 162 163 # Once we're there, store the back state. We'll use that to jump 164 # back to our current location once the edit is done. 165 assert self._pre_game_add_state is None 166 self._pre_game_add_state = addwindow.main_window_back_state 167 168 def edit_game_pressed(self, from_window: bui.MainWindow) -> None: 169 """Should be called by supplemental UIs when a game is to be edited.""" 170 171 if not self._playlist: 172 return 173 174 self._show_edit_ui( 175 gametype=bui.getclass( 176 self._playlist[self._selected_index]['type'], 177 subclassof=bs.GameActivity, 178 ), 179 settings=self._playlist[self._selected_index], 180 from_window=from_window, 181 ) 182 183 def _show_edit_ui( 184 self, 185 gametype: type[bs.GameActivity], 186 settings: dict[str, Any] | None, 187 from_window: bui.MainWindow, 188 ) -> None: 189 # pylint: disable=cyclic-import 190 from bauiv1lib.playlist.editgame import PlaylistEditGameWindow 191 192 if not from_window.main_window_has_control(): 193 return 194 195 self._editing_game = settings is not None 196 self._editing_game_type = gametype 197 assert self._sessiontype is not None 198 199 # Jump into an edit window. 200 editwindow = PlaylistEditGameWindow( 201 gametype, 202 self._sessiontype, 203 copy.deepcopy(settings), 204 completion_call=self._edit_game_done, 205 ) 206 from_window.main_window_replace(editwindow) 207 208 # Once we're there, store the back state. We'll use that to jump 209 # back to our current location once the edit is done. 210 assert self._pre_game_edit_state is None 211 self._pre_game_edit_state = editwindow.main_window_back_state 212 213 def add_game_type_selected( 214 self, gametype: type[bs.GameActivity], from_window: bui.MainWindow 215 ) -> None: 216 """(internal)""" 217 self._show_edit_ui( 218 gametype=gametype, settings=None, from_window=from_window 219 ) 220 221 def _edit_game_done( 222 self, config: dict[str, Any] | None, from_window: bui.MainWindow 223 ) -> None: 224 225 # No-op if provided window isn't in charge. 226 if not from_window.main_window_has_control(): 227 return 228 229 assert bui.app.classic is not None 230 if config is None: 231 bui.getsound('powerdown01').play() 232 else: 233 # Make sure type is in there. 234 assert self._editing_game_type is not None 235 config['type'] = bui.get_type_name(self._editing_game_type) 236 237 if self._editing_game: 238 self._playlist[self._selected_index] = copy.deepcopy(config) 239 else: 240 # Add a new entry to the playlist. 241 insert_index = min( 242 len(self._playlist), self._selected_index + 1 243 ) 244 self._playlist.insert(insert_index, copy.deepcopy(config)) 245 self._selected_index = insert_index 246 247 bui.getsound('gunCocking').play() 248 249 # If we're adding, jump to before the add started. 250 # Otherwise jump to before the edit started. 251 assert ( 252 self._pre_game_edit_state is not None 253 or self._pre_game_add_state is not None 254 ) 255 if self._pre_game_add_state is not None: 256 from_window.main_window_back_state = self._pre_game_add_state 257 elif self._pre_game_edit_state is not None: 258 from_window.main_window_back_state = self._pre_game_edit_state 259 from_window.main_window_back() 260 self._pre_game_edit_state = None 261 self._pre_game_add_state = None
Coordinates various UIs involved in playlist editing.
PlaylistEditController( sessiontype: type[bascenev1.Session], from_window: bauiv1.MainWindow, existing_playlist_name: str | None = None, playlist: list[dict[str, typing.Any]] | None = None, playlist_name: str | None = None)
21 def __init__( 22 self, 23 sessiontype: type[bs.Session], 24 from_window: bui.MainWindow, 25 existing_playlist_name: str | None = None, 26 playlist: list[dict[str, Any]] | None = None, 27 playlist_name: str | None = None, 28 ): 29 from bascenev1 import filter_playlist 30 from bauiv1lib.playlist import PlaylistTypeVars 31 from bauiv1lib.playlist.edit import PlaylistEditWindow 32 33 appconfig = bui.app.config 34 35 # Since we may be showing our map list momentarily, 36 # lets go ahead and preload all map preview textures. 37 if bui.app.classic is not None: 38 bui.app.classic.preload_map_preview_media() 39 40 self._sessiontype = sessiontype 41 42 self._editing_game = False 43 self._editing_game_type: type[bs.GameActivity] | None = None 44 self._pvars = PlaylistTypeVars(sessiontype) 45 self._existing_playlist_name = existing_playlist_name 46 self._config_name_full = self._pvars.config_name + ' Playlists' 47 48 self._pre_game_add_state: bui.MainWindowState | None = None 49 self._pre_game_edit_state: bui.MainWindowState | None = None 50 51 # Make sure config exists. 52 if self._config_name_full not in appconfig: 53 appconfig[self._config_name_full] = {} 54 55 self._selected_index = 0 56 if existing_playlist_name: 57 self._name = existing_playlist_name 58 59 # Filter out invalid games. 60 self._playlist = filter_playlist( 61 appconfig[self._pvars.config_name + ' Playlists'][ 62 existing_playlist_name 63 ], 64 sessiontype=sessiontype, 65 remove_unowned=False, 66 name=existing_playlist_name, 67 ) 68 self._edit_ui_selection = None 69 else: 70 if playlist is not None: 71 self._playlist = playlist 72 else: 73 self._playlist = [] 74 if playlist_name is not None: 75 self._name = playlist_name 76 else: 77 # Find a good unused name. 78 i = 1 79 while True: 80 self._name = ( 81 self._pvars.default_new_list_name.evaluate() 82 + ((' ' + str(i)) if i > 1 else '') 83 ) 84 if ( 85 self._name 86 not in appconfig[self._pvars.config_name + ' Playlists'] 87 ): 88 break 89 i += 1 90 91 # Also we want it to start with 'add' highlighted since its empty 92 # and that's all they can do. 93 self._edit_ui_selection = 'add_button' 94 95 editwindow = PlaylistEditWindow(editcontroller=self) 96 from_window.main_window_replace(editwindow) 97 98 # Once we've set our start window, store the back state. We'll 99 # skip back to there once we're fully done. 100 self._back_state = editwindow.main_window_back_state
def
get_playlist(self) -> list[dict[str, typing.Any]]:
126 def get_playlist(self) -> list[dict[str, Any]]: 127 """Return the current state of the edited playlist.""" 128 return copy.deepcopy(self._playlist)
Return the current state of the edited playlist.
def
set_playlist(self, playlist: list[dict[str, typing.Any]]) -> None:
130 def set_playlist(self, playlist: list[dict[str, Any]]) -> None: 131 """Set the playlist contents.""" 132 self._playlist = copy.deepcopy(playlist)
Set the playlist contents.
134 def get_session_type(self) -> type[bs.Session]: 135 """Return the bascenev1.Session type for this edit-session.""" 136 return self._sessiontype
Return the bascenev1.Session type for this edit-session.
def
get_selected_index(self) -> int:
138 def get_selected_index(self) -> int: 139 """Return the index of the selected playlist.""" 140 return self._selected_index
Return the index of the selected playlist.
def
set_selected_index(self, index: int) -> None:
146 def set_selected_index(self, index: int) -> None: 147 """Sets the selected playlist index.""" 148 self._selected_index = index
Sets the selected playlist index.
168 def edit_game_pressed(self, from_window: bui.MainWindow) -> None: 169 """Should be called by supplemental UIs when a game is to be edited.""" 170 171 if not self._playlist: 172 return 173 174 self._show_edit_ui( 175 gametype=bui.getclass( 176 self._playlist[self._selected_index]['type'], 177 subclassof=bs.GameActivity, 178 ), 179 settings=self._playlist[self._selected_index], 180 from_window=from_window, 181 )
Should be called by supplemental UIs when a game is to be edited.