bauiv1lib.soundtrack.entrytypeselect

Provides UI for selecting soundtrack entry types.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides UI for selecting soundtrack entry types."""
  4from __future__ import annotations
  5
  6import copy
  7from typing import TYPE_CHECKING, override
  8
  9import bauiv1 as bui
 10
 11if TYPE_CHECKING:
 12    from typing import Any, Callable
 13
 14
 15class SoundtrackEntryTypeSelectWindow(bui.MainWindow):
 16    """Window for selecting a soundtrack entry type."""
 17
 18    def __init__(
 19        self,
 20        callback: Callable[[Any], Any],
 21        current_entry: Any,
 22        selection_target_name: str,
 23        *,
 24        transition: str | None = 'in_right',
 25        origin_widget: bui.Widget | None = None,
 26    ):
 27        # pylint: disable=too-many-locals
 28        assert bui.app.classic is not None
 29        music = bui.app.classic.music
 30        self._r = 'editSoundtrackWindow'
 31
 32        self._selection_target_name = selection_target_name
 33        self._callback = callback
 34        self._current_entry = copy.deepcopy(current_entry)
 35
 36        self._width = 580
 37        self._height = 220
 38        spacing = 80
 39
 40        # FIXME: Generalize this so new custom soundtrack types can add
 41        # themselves here.
 42        do_default = True
 43        do_mac_music_app_playlist = music.supports_soundtrack_entry_type(
 44            'iTunesPlaylist'
 45        )
 46        do_music_file = music.supports_soundtrack_entry_type('musicFile')
 47        do_music_folder = music.supports_soundtrack_entry_type('musicFolder')
 48
 49        if do_mac_music_app_playlist:
 50            self._height += spacing
 51        if do_music_file:
 52            self._height += spacing
 53        if do_music_folder:
 54            self._height += spacing
 55
 56        uiscale = bui.app.ui_v1.uiscale
 57
 58        # NOTE: When something is selected, we close our UI and kick off
 59        # another window which then calls us back when its done, so the
 60        # standard UI-cleanup-check complains that something is holding
 61        # on to our instance after its ui is gone. Should restructure in
 62        # a cleaner way, but just disabling that check for now.
 63        super().__init__(
 64            root_widget=bui.containerwidget(
 65                size=(self._width, self._height),
 66                scale=(
 67                    1.7
 68                    if uiscale is bui.UIScale.SMALL
 69                    else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
 70                ),
 71            ),
 72            cleanupcheck=False,
 73            transition=transition,
 74            origin_widget=origin_widget,
 75        )
 76        btn = bui.buttonwidget(
 77            parent=self._root_widget,
 78            position=(35, self._height - 65),
 79            size=(160, 60),
 80            scale=0.8,
 81            text_scale=1.2,
 82            label=bui.Lstr(resource='cancelText'),
 83            on_activate_call=self._on_cancel_press,
 84        )
 85        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
 86        bui.textwidget(
 87            parent=self._root_widget,
 88            position=(self._width * 0.5, self._height - 32),
 89            size=(0, 0),
 90            text=bui.Lstr(resource=f'{self._r}.selectASourceText'),
 91            color=bui.app.ui_v1.title_color,
 92            maxwidth=230,
 93            h_align='center',
 94            v_align='center',
 95        )
 96
 97        bui.textwidget(
 98            parent=self._root_widget,
 99            position=(self._width * 0.5, self._height - 56),
100            size=(0, 0),
101            text=selection_target_name,
102            color=bui.app.ui_v1.infotextcolor,
103            scale=0.7,
104            maxwidth=230,
105            h_align='center',
106            v_align='center',
107        )
108
109        v = self._height - 155
110
111        current_entry_type = music.get_soundtrack_entry_type(current_entry)
112
113        if do_default:
114            btn = bui.buttonwidget(
115                parent=self._root_widget,
116                size=(self._width - 100, 60),
117                position=(50, v),
118                label=bui.Lstr(resource=f'{self._r}.useDefaultGameMusicText'),
119                on_activate_call=self._on_default_press,
120            )
121            if current_entry_type == 'default':
122                bui.containerwidget(edit=self._root_widget, selected_child=btn)
123            v -= spacing
124
125        if do_mac_music_app_playlist:
126            btn = bui.buttonwidget(
127                parent=self._root_widget,
128                size=(self._width - 100, 60),
129                position=(50, v),
130                label=bui.Lstr(resource=f'{self._r}.useITunesPlaylistText'),
131                on_activate_call=self._on_mac_music_app_playlist_press,
132                icon=None,
133            )
134            if current_entry_type == 'iTunesPlaylist':
135                bui.containerwidget(edit=self._root_widget, selected_child=btn)
136            v -= spacing
137
138        if do_music_file:
139            btn = bui.buttonwidget(
140                parent=self._root_widget,
141                size=(self._width - 100, 60),
142                position=(50, v),
143                label=bui.Lstr(resource=f'{self._r}.useMusicFileText'),
144                on_activate_call=self._on_music_file_press,
145                icon=bui.gettexture('file'),
146            )
147            if current_entry_type == 'musicFile':
148                bui.containerwidget(edit=self._root_widget, selected_child=btn)
149            v -= spacing
150
151        if do_music_folder:
152            btn = bui.buttonwidget(
153                parent=self._root_widget,
154                size=(self._width - 100, 60),
155                position=(50, v),
156                label=bui.Lstr(resource=f'{self._r}.useMusicFolderText'),
157                on_activate_call=self._on_music_folder_press,
158                icon=bui.gettexture('folder'),
159                icon_color=(1.1, 0.8, 0.2),
160            )
161            if current_entry_type == 'musicFolder':
162                bui.containerwidget(edit=self._root_widget, selected_child=btn)
163            v -= spacing
164
165    @override
166    def get_main_window_state(self) -> bui.MainWindowState:
167        # Support recreating our window for back/refresh purposes.
168        cls = type(self)
169
170        # Pull these out of self here; if we reference self in the
171        # lambda we'll keep our window alive which is bad.
172        current_entry = self._current_entry
173        callback = self._callback
174        selection_target_name = self._selection_target_name
175
176        return bui.BasicMainWindowState(
177            create_call=lambda transition, origin_widget: cls(
178                transition=transition,
179                origin_widget=origin_widget,
180                current_entry=current_entry,
181                callback=callback,
182                selection_target_name=selection_target_name,
183            )
184        )
185
186    def _on_mac_music_app_playlist_press(self) -> None:
187        assert bui.app.classic is not None
188        music = bui.app.classic.music
189        from bauiv1lib.soundtrack.macmusicapp import (
190            MacMusicAppPlaylistSelectWindow,
191        )
192
193        # no-op if we're not in control.
194        if not self.main_window_has_control():
195            return
196
197        current_playlist_entry: str | None
198        if (
199            music.get_soundtrack_entry_type(self._current_entry)
200            == 'iTunesPlaylist'
201        ):
202            current_playlist_entry = music.get_soundtrack_entry_name(
203                self._current_entry
204            )
205        else:
206            current_playlist_entry = None
207
208        self.main_window_replace(
209            MacMusicAppPlaylistSelectWindow(
210                self._callback, current_playlist_entry, self._current_entry
211            )
212        )
213
214    def _on_music_file_press(self) -> None:
215        from babase import android_get_external_files_dir
216        from baclassic.osmusic import OSMusicPlayer
217        from bauiv1lib.fileselector import FileSelectorWindow
218
219        # no-op if we're not in control.
220        if not self.main_window_has_control():
221            return
222
223        base_path = android_get_external_files_dir()
224        assert bui.app.classic is not None
225
226        self.main_window_replace(
227            FileSelectorWindow(
228                base_path,
229                callback=self._music_file_selector_cb,
230                show_base_path=False,
231                valid_file_extensions=(
232                    OSMusicPlayer.get_valid_music_file_extensions()
233                ),
234                allow_folders=False,
235            ),
236        )
237
238    def _on_music_folder_press(self) -> None:
239        from bauiv1lib.fileselector import FileSelectorWindow
240        from babase import android_get_external_files_dir
241
242        # no-op if we're not in control.
243        if not self.main_window_has_control():
244            return
245
246        base_path = android_get_external_files_dir()
247        assert bui.app.classic is not None
248
249        self.main_window_replace(
250            FileSelectorWindow(
251                base_path,
252                callback=self._music_folder_selector_cb,
253                show_base_path=False,
254                valid_file_extensions=[],
255                allow_folders=True,
256            ),
257        )
258
259    def _music_file_selector_cb(self, result: str | None) -> None:
260        if result is None:
261            self._callback(self._current_entry)
262        else:
263            self._callback({'type': 'musicFile', 'name': result})
264
265    def _music_folder_selector_cb(self, result: str | None) -> None:
266        if result is None:
267            self._callback(self._current_entry)
268        else:
269            self._callback({'type': 'musicFolder', 'name': result})
270
271    def _on_default_press(self) -> None:
272        self.main_window_back()
273        self._callback(None)
274
275    def _on_cancel_press(self) -> None:
276        self.main_window_back()
277        self._callback(self._current_entry)
class SoundtrackEntryTypeSelectWindow(bauiv1._uitypes.MainWindow):
 16class SoundtrackEntryTypeSelectWindow(bui.MainWindow):
 17    """Window for selecting a soundtrack entry type."""
 18
 19    def __init__(
 20        self,
 21        callback: Callable[[Any], Any],
 22        current_entry: Any,
 23        selection_target_name: str,
 24        *,
 25        transition: str | None = 'in_right',
 26        origin_widget: bui.Widget | None = None,
 27    ):
 28        # pylint: disable=too-many-locals
 29        assert bui.app.classic is not None
 30        music = bui.app.classic.music
 31        self._r = 'editSoundtrackWindow'
 32
 33        self._selection_target_name = selection_target_name
 34        self._callback = callback
 35        self._current_entry = copy.deepcopy(current_entry)
 36
 37        self._width = 580
 38        self._height = 220
 39        spacing = 80
 40
 41        # FIXME: Generalize this so new custom soundtrack types can add
 42        # themselves here.
 43        do_default = True
 44        do_mac_music_app_playlist = music.supports_soundtrack_entry_type(
 45            'iTunesPlaylist'
 46        )
 47        do_music_file = music.supports_soundtrack_entry_type('musicFile')
 48        do_music_folder = music.supports_soundtrack_entry_type('musicFolder')
 49
 50        if do_mac_music_app_playlist:
 51            self._height += spacing
 52        if do_music_file:
 53            self._height += spacing
 54        if do_music_folder:
 55            self._height += spacing
 56
 57        uiscale = bui.app.ui_v1.uiscale
 58
 59        # NOTE: When something is selected, we close our UI and kick off
 60        # another window which then calls us back when its done, so the
 61        # standard UI-cleanup-check complains that something is holding
 62        # on to our instance after its ui is gone. Should restructure in
 63        # a cleaner way, but just disabling that check for now.
 64        super().__init__(
 65            root_widget=bui.containerwidget(
 66                size=(self._width, self._height),
 67                scale=(
 68                    1.7
 69                    if uiscale is bui.UIScale.SMALL
 70                    else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
 71                ),
 72            ),
 73            cleanupcheck=False,
 74            transition=transition,
 75            origin_widget=origin_widget,
 76        )
 77        btn = bui.buttonwidget(
 78            parent=self._root_widget,
 79            position=(35, self._height - 65),
 80            size=(160, 60),
 81            scale=0.8,
 82            text_scale=1.2,
 83            label=bui.Lstr(resource='cancelText'),
 84            on_activate_call=self._on_cancel_press,
 85        )
 86        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
 87        bui.textwidget(
 88            parent=self._root_widget,
 89            position=(self._width * 0.5, self._height - 32),
 90            size=(0, 0),
 91            text=bui.Lstr(resource=f'{self._r}.selectASourceText'),
 92            color=bui.app.ui_v1.title_color,
 93            maxwidth=230,
 94            h_align='center',
 95            v_align='center',
 96        )
 97
 98        bui.textwidget(
 99            parent=self._root_widget,
100            position=(self._width * 0.5, self._height - 56),
101            size=(0, 0),
102            text=selection_target_name,
103            color=bui.app.ui_v1.infotextcolor,
104            scale=0.7,
105            maxwidth=230,
106            h_align='center',
107            v_align='center',
108        )
109
110        v = self._height - 155
111
112        current_entry_type = music.get_soundtrack_entry_type(current_entry)
113
114        if do_default:
115            btn = bui.buttonwidget(
116                parent=self._root_widget,
117                size=(self._width - 100, 60),
118                position=(50, v),
119                label=bui.Lstr(resource=f'{self._r}.useDefaultGameMusicText'),
120                on_activate_call=self._on_default_press,
121            )
122            if current_entry_type == 'default':
123                bui.containerwidget(edit=self._root_widget, selected_child=btn)
124            v -= spacing
125
126        if do_mac_music_app_playlist:
127            btn = bui.buttonwidget(
128                parent=self._root_widget,
129                size=(self._width - 100, 60),
130                position=(50, v),
131                label=bui.Lstr(resource=f'{self._r}.useITunesPlaylistText'),
132                on_activate_call=self._on_mac_music_app_playlist_press,
133                icon=None,
134            )
135            if current_entry_type == 'iTunesPlaylist':
136                bui.containerwidget(edit=self._root_widget, selected_child=btn)
137            v -= spacing
138
139        if do_music_file:
140            btn = bui.buttonwidget(
141                parent=self._root_widget,
142                size=(self._width - 100, 60),
143                position=(50, v),
144                label=bui.Lstr(resource=f'{self._r}.useMusicFileText'),
145                on_activate_call=self._on_music_file_press,
146                icon=bui.gettexture('file'),
147            )
148            if current_entry_type == 'musicFile':
149                bui.containerwidget(edit=self._root_widget, selected_child=btn)
150            v -= spacing
151
152        if do_music_folder:
153            btn = bui.buttonwidget(
154                parent=self._root_widget,
155                size=(self._width - 100, 60),
156                position=(50, v),
157                label=bui.Lstr(resource=f'{self._r}.useMusicFolderText'),
158                on_activate_call=self._on_music_folder_press,
159                icon=bui.gettexture('folder'),
160                icon_color=(1.1, 0.8, 0.2),
161            )
162            if current_entry_type == 'musicFolder':
163                bui.containerwidget(edit=self._root_widget, selected_child=btn)
164            v -= spacing
165
166    @override
167    def get_main_window_state(self) -> bui.MainWindowState:
168        # Support recreating our window for back/refresh purposes.
169        cls = type(self)
170
171        # Pull these out of self here; if we reference self in the
172        # lambda we'll keep our window alive which is bad.
173        current_entry = self._current_entry
174        callback = self._callback
175        selection_target_name = self._selection_target_name
176
177        return bui.BasicMainWindowState(
178            create_call=lambda transition, origin_widget: cls(
179                transition=transition,
180                origin_widget=origin_widget,
181                current_entry=current_entry,
182                callback=callback,
183                selection_target_name=selection_target_name,
184            )
185        )
186
187    def _on_mac_music_app_playlist_press(self) -> None:
188        assert bui.app.classic is not None
189        music = bui.app.classic.music
190        from bauiv1lib.soundtrack.macmusicapp import (
191            MacMusicAppPlaylistSelectWindow,
192        )
193
194        # no-op if we're not in control.
195        if not self.main_window_has_control():
196            return
197
198        current_playlist_entry: str | None
199        if (
200            music.get_soundtrack_entry_type(self._current_entry)
201            == 'iTunesPlaylist'
202        ):
203            current_playlist_entry = music.get_soundtrack_entry_name(
204                self._current_entry
205            )
206        else:
207            current_playlist_entry = None
208
209        self.main_window_replace(
210            MacMusicAppPlaylistSelectWindow(
211                self._callback, current_playlist_entry, self._current_entry
212            )
213        )
214
215    def _on_music_file_press(self) -> None:
216        from babase import android_get_external_files_dir
217        from baclassic.osmusic import OSMusicPlayer
218        from bauiv1lib.fileselector import FileSelectorWindow
219
220        # no-op if we're not in control.
221        if not self.main_window_has_control():
222            return
223
224        base_path = android_get_external_files_dir()
225        assert bui.app.classic is not None
226
227        self.main_window_replace(
228            FileSelectorWindow(
229                base_path,
230                callback=self._music_file_selector_cb,
231                show_base_path=False,
232                valid_file_extensions=(
233                    OSMusicPlayer.get_valid_music_file_extensions()
234                ),
235                allow_folders=False,
236            ),
237        )
238
239    def _on_music_folder_press(self) -> None:
240        from bauiv1lib.fileselector import FileSelectorWindow
241        from babase import android_get_external_files_dir
242
243        # no-op if we're not in control.
244        if not self.main_window_has_control():
245            return
246
247        base_path = android_get_external_files_dir()
248        assert bui.app.classic is not None
249
250        self.main_window_replace(
251            FileSelectorWindow(
252                base_path,
253                callback=self._music_folder_selector_cb,
254                show_base_path=False,
255                valid_file_extensions=[],
256                allow_folders=True,
257            ),
258        )
259
260    def _music_file_selector_cb(self, result: str | None) -> None:
261        if result is None:
262            self._callback(self._current_entry)
263        else:
264            self._callback({'type': 'musicFile', 'name': result})
265
266    def _music_folder_selector_cb(self, result: str | None) -> None:
267        if result is None:
268            self._callback(self._current_entry)
269        else:
270            self._callback({'type': 'musicFolder', 'name': result})
271
272    def _on_default_press(self) -> None:
273        self.main_window_back()
274        self._callback(None)
275
276    def _on_cancel_press(self) -> None:
277        self.main_window_back()
278        self._callback(self._current_entry)

Window for selecting a soundtrack entry type.

SoundtrackEntryTypeSelectWindow( callback: Callable[[Any], Any], current_entry: Any, selection_target_name: str, *, transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
 19    def __init__(
 20        self,
 21        callback: Callable[[Any], Any],
 22        current_entry: Any,
 23        selection_target_name: str,
 24        *,
 25        transition: str | None = 'in_right',
 26        origin_widget: bui.Widget | None = None,
 27    ):
 28        # pylint: disable=too-many-locals
 29        assert bui.app.classic is not None
 30        music = bui.app.classic.music
 31        self._r = 'editSoundtrackWindow'
 32
 33        self._selection_target_name = selection_target_name
 34        self._callback = callback
 35        self._current_entry = copy.deepcopy(current_entry)
 36
 37        self._width = 580
 38        self._height = 220
 39        spacing = 80
 40
 41        # FIXME: Generalize this so new custom soundtrack types can add
 42        # themselves here.
 43        do_default = True
 44        do_mac_music_app_playlist = music.supports_soundtrack_entry_type(
 45            'iTunesPlaylist'
 46        )
 47        do_music_file = music.supports_soundtrack_entry_type('musicFile')
 48        do_music_folder = music.supports_soundtrack_entry_type('musicFolder')
 49
 50        if do_mac_music_app_playlist:
 51            self._height += spacing
 52        if do_music_file:
 53            self._height += spacing
 54        if do_music_folder:
 55            self._height += spacing
 56
 57        uiscale = bui.app.ui_v1.uiscale
 58
 59        # NOTE: When something is selected, we close our UI and kick off
 60        # another window which then calls us back when its done, so the
 61        # standard UI-cleanup-check complains that something is holding
 62        # on to our instance after its ui is gone. Should restructure in
 63        # a cleaner way, but just disabling that check for now.
 64        super().__init__(
 65            root_widget=bui.containerwidget(
 66                size=(self._width, self._height),
 67                scale=(
 68                    1.7
 69                    if uiscale is bui.UIScale.SMALL
 70                    else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
 71                ),
 72            ),
 73            cleanupcheck=False,
 74            transition=transition,
 75            origin_widget=origin_widget,
 76        )
 77        btn = bui.buttonwidget(
 78            parent=self._root_widget,
 79            position=(35, self._height - 65),
 80            size=(160, 60),
 81            scale=0.8,
 82            text_scale=1.2,
 83            label=bui.Lstr(resource='cancelText'),
 84            on_activate_call=self._on_cancel_press,
 85        )
 86        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
 87        bui.textwidget(
 88            parent=self._root_widget,
 89            position=(self._width * 0.5, self._height - 32),
 90            size=(0, 0),
 91            text=bui.Lstr(resource=f'{self._r}.selectASourceText'),
 92            color=bui.app.ui_v1.title_color,
 93            maxwidth=230,
 94            h_align='center',
 95            v_align='center',
 96        )
 97
 98        bui.textwidget(
 99            parent=self._root_widget,
100            position=(self._width * 0.5, self._height - 56),
101            size=(0, 0),
102            text=selection_target_name,
103            color=bui.app.ui_v1.infotextcolor,
104            scale=0.7,
105            maxwidth=230,
106            h_align='center',
107            v_align='center',
108        )
109
110        v = self._height - 155
111
112        current_entry_type = music.get_soundtrack_entry_type(current_entry)
113
114        if do_default:
115            btn = bui.buttonwidget(
116                parent=self._root_widget,
117                size=(self._width - 100, 60),
118                position=(50, v),
119                label=bui.Lstr(resource=f'{self._r}.useDefaultGameMusicText'),
120                on_activate_call=self._on_default_press,
121            )
122            if current_entry_type == 'default':
123                bui.containerwidget(edit=self._root_widget, selected_child=btn)
124            v -= spacing
125
126        if do_mac_music_app_playlist:
127            btn = bui.buttonwidget(
128                parent=self._root_widget,
129                size=(self._width - 100, 60),
130                position=(50, v),
131                label=bui.Lstr(resource=f'{self._r}.useITunesPlaylistText'),
132                on_activate_call=self._on_mac_music_app_playlist_press,
133                icon=None,
134            )
135            if current_entry_type == 'iTunesPlaylist':
136                bui.containerwidget(edit=self._root_widget, selected_child=btn)
137            v -= spacing
138
139        if do_music_file:
140            btn = bui.buttonwidget(
141                parent=self._root_widget,
142                size=(self._width - 100, 60),
143                position=(50, v),
144                label=bui.Lstr(resource=f'{self._r}.useMusicFileText'),
145                on_activate_call=self._on_music_file_press,
146                icon=bui.gettexture('file'),
147            )
148            if current_entry_type == 'musicFile':
149                bui.containerwidget(edit=self._root_widget, selected_child=btn)
150            v -= spacing
151
152        if do_music_folder:
153            btn = bui.buttonwidget(
154                parent=self._root_widget,
155                size=(self._width - 100, 60),
156                position=(50, v),
157                label=bui.Lstr(resource=f'{self._r}.useMusicFolderText'),
158                on_activate_call=self._on_music_folder_press,
159                icon=bui.gettexture('folder'),
160                icon_color=(1.1, 0.8, 0.2),
161            )
162            if current_entry_type == 'musicFolder':
163                bui.containerwidget(edit=self._root_widget, selected_child=btn)
164            v -= spacing

Create a MainWindow given a root widget and transition info.

Automatically handles in and out transitions on the provided widget, so there is no need to set transitions when creating it.

@override
def get_main_window_state(self) -> bauiv1.MainWindowState:
166    @override
167    def get_main_window_state(self) -> bui.MainWindowState:
168        # Support recreating our window for back/refresh purposes.
169        cls = type(self)
170
171        # Pull these out of self here; if we reference self in the
172        # lambda we'll keep our window alive which is bad.
173        current_entry = self._current_entry
174        callback = self._callback
175        selection_target_name = self._selection_target_name
176
177        return bui.BasicMainWindowState(
178            create_call=lambda transition, origin_widget: cls(
179                transition=transition,
180                origin_widget=origin_widget,
181                current_entry=current_entry,
182                callback=callback,
183                selection_target_name=selection_target_name,
184            )
185        )

Return a WindowState to recreate this window, if supported.