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

Window for editing an individual game playlist.

PlaylistEditWindow( 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        # 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        uiscale = ba.app.ui.uiscale
 33        self._width = 770 if uiscale is ba.UIScale.SMALL else 670
 34        x_inset = 50 if uiscale is ba.UIScale.SMALL else 0
 35        self._height = (
 36            400
 37            if uiscale is ba.UIScale.SMALL
 38            else 470
 39            if uiscale is ba.UIScale.MEDIUM
 40            else 540
 41        )
 42
 43        top_extra = 20 if uiscale is ba.UIScale.SMALL else 0
 44        super().__init__(
 45            root_widget=ba.containerwidget(
 46                size=(self._width, self._height + top_extra),
 47                transition=transition,
 48                scale=(
 49                    2.0
 50                    if uiscale is ba.UIScale.SMALL
 51                    else 1.3
 52                    if uiscale is ba.UIScale.MEDIUM
 53                    else 1.0
 54                ),
 55                stack_offset=(0, -16)
 56                if uiscale is ba.UIScale.SMALL
 57                else (0, 0),
 58            )
 59        )
 60        cancel_button = ba.buttonwidget(
 61            parent=self._root_widget,
 62            position=(35 + x_inset, self._height - 60),
 63            scale=0.8,
 64            size=(175, 60),
 65            autoselect=True,
 66            label=ba.Lstr(resource='cancelText'),
 67            text_scale=1.2,
 68        )
 69        save_button = btn = ba.buttonwidget(
 70            parent=self._root_widget,
 71            position=(self._width - (195 + x_inset), self._height - 60),
 72            scale=0.8,
 73            size=(190, 60),
 74            autoselect=True,
 75            left_widget=cancel_button,
 76            label=ba.Lstr(resource='saveText'),
 77            text_scale=1.2,
 78        )
 79
 80        if ba.app.ui.use_toolbars:
 81            ba.widget(
 82                edit=btn,
 83                right_widget=ba.internal.get_special_widget('party_button'),
 84            )
 85
 86        ba.widget(
 87            edit=cancel_button,
 88            left_widget=cancel_button,
 89            right_widget=save_button,
 90        )
 91
 92        ba.textwidget(
 93            parent=self._root_widget,
 94            position=(-10, self._height - 50),
 95            size=(self._width, 25),
 96            text=ba.Lstr(resource=self._r + '.titleText'),
 97            color=ba.app.ui.title_color,
 98            scale=1.05,
 99            h_align='center',
100            v_align='center',
101            maxwidth=270,
102        )
103
104        v = self._height - 115.0
105
106        self._scroll_width = self._width - (205 + 2 * x_inset)
107
108        ba.textwidget(
109            parent=self._root_widget,
110            text=ba.Lstr(resource=self._r + '.listNameText'),
111            position=(196 + x_inset, v + 31),
112            maxwidth=150,
113            color=(0.8, 0.8, 0.8, 0.5),
114            size=(0, 0),
115            scale=0.75,
116            h_align='right',
117            v_align='center',
118        )
119
120        self._text_field = ba.textwidget(
121            parent=self._root_widget,
122            position=(210 + x_inset, v + 7),
123            size=(self._scroll_width - 53, 43),
124            text=self._editcontroller.getname(),
125            h_align='left',
126            v_align='center',
127            max_chars=40,
128            autoselect=True,
129            color=(0.9, 0.9, 0.9, 1.0),
130            description=ba.Lstr(resource=self._r + '.listNameText'),
131            editable=True,
132            padding=4,
133            on_return_press_call=self._save_press_with_sound,
134        )
135        ba.widget(edit=cancel_button, down_widget=self._text_field)
136
137        self._list_widgets: list[ba.Widget] = []
138
139        h = 40 + x_inset
140        v = self._height - 172.0
141
142        b_color = (0.6, 0.53, 0.63)
143        b_textcolor = (0.75, 0.7, 0.8)
144
145        v -= 2.0
146        v += 63
147
148        scl = (
149            1.03
150            if uiscale is ba.UIScale.SMALL
151            else 1.36
152            if uiscale is ba.UIScale.MEDIUM
153            else 1.74
154        )
155        v -= 63.0 * scl
156
157        add_game_button = ba.buttonwidget(
158            parent=self._root_widget,
159            position=(h, v),
160            size=(110, 61.0 * scl),
161            on_activate_call=self._add,
162            on_select_call=ba.Call(self._set_ui_selection, 'add_button'),
163            autoselect=True,
164            button_type='square',
165            color=b_color,
166            textcolor=b_textcolor,
167            text_scale=0.8,
168            label=ba.Lstr(resource=self._r + '.addGameText'),
169        )
170        ba.widget(edit=add_game_button, up_widget=self._text_field)
171        v -= 63.0 * scl
172
173        self._edit_button = edit_game_button = ba.buttonwidget(
174            parent=self._root_widget,
175            position=(h, v),
176            size=(110, 61.0 * scl),
177            on_activate_call=self._edit,
178            on_select_call=ba.Call(self._set_ui_selection, 'editButton'),
179            autoselect=True,
180            button_type='square',
181            color=b_color,
182            textcolor=b_textcolor,
183            text_scale=0.8,
184            label=ba.Lstr(resource=self._r + '.editGameText'),
185        )
186        v -= 63.0 * scl
187
188        remove_game_button = ba.buttonwidget(
189            parent=self._root_widget,
190            position=(h, v),
191            size=(110, 61.0 * scl),
192            text_scale=0.8,
193            on_activate_call=self._remove,
194            autoselect=True,
195            button_type='square',
196            color=b_color,
197            textcolor=b_textcolor,
198            label=ba.Lstr(resource=self._r + '.removeGameText'),
199        )
200        v -= 40
201        h += 9
202        ba.buttonwidget(
203            parent=self._root_widget,
204            position=(h, v),
205            size=(42, 35),
206            on_activate_call=self._move_up,
207            label=ba.charstr(ba.SpecialChar.UP_ARROW),
208            button_type='square',
209            color=b_color,
210            textcolor=b_textcolor,
211            autoselect=True,
212            repeat=True,
213        )
214        h += 52
215        ba.buttonwidget(
216            parent=self._root_widget,
217            position=(h, v),
218            size=(42, 35),
219            on_activate_call=self._move_down,
220            autoselect=True,
221            button_type='square',
222            color=b_color,
223            textcolor=b_textcolor,
224            label=ba.charstr(ba.SpecialChar.DOWN_ARROW),
225            repeat=True,
226        )
227
228        v = self._height - 100
229        scroll_height = self._height - 155
230        scrollwidget = ba.scrollwidget(
231            parent=self._root_widget,
232            position=(160 + x_inset, v - scroll_height),
233            highlight=False,
234            on_select_call=ba.Call(self._set_ui_selection, 'gameList'),
235            size=(self._scroll_width, (scroll_height - 15)),
236        )
237        ba.widget(
238            edit=scrollwidget,
239            left_widget=add_game_button,
240            right_widget=scrollwidget,
241        )
242        self._columnwidget = ba.columnwidget(
243            parent=scrollwidget, border=2, margin=0
244        )
245        ba.widget(edit=self._columnwidget, up_widget=self._text_field)
246
247        for button in [add_game_button, edit_game_button, remove_game_button]:
248            ba.widget(
249                edit=button, left_widget=button, right_widget=scrollwidget
250            )
251
252        self._refresh()
253
254        ba.buttonwidget(edit=cancel_button, on_activate_call=self._cancel)
255        ba.containerwidget(
256            edit=self._root_widget,
257            cancel_button=cancel_button,
258            selected_child=scrollwidget,
259        )
260
261        ba.buttonwidget(edit=save_button, on_activate_call=self._save_press)
262        ba.containerwidget(edit=self._root_widget, start_button=save_button)
263
264        if prev_selection == 'add_button':
265            ba.containerwidget(
266                edit=self._root_widget, selected_child=add_game_button
267            )
268        elif prev_selection == 'editButton':
269            ba.containerwidget(
270                edit=self._root_widget, selected_child=edit_game_button
271            )
272        elif prev_selection == 'gameList':
273            ba.containerwidget(
274                edit=self._root_widget, selected_child=scrollwidget
275            )
Inherited Members
ba.ui.Window
get_root_widget