bauiv1lib.settings.audio

Provides audio settings UI.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides audio settings UI."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING, override
  8import logging
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    pass
 14
 15
 16class AudioSettingsWindow(bui.MainWindow):
 17    """Window for editing audio settings."""
 18
 19    def __init__(
 20        self,
 21        transition: str | None = 'in_right',
 22        origin_widget: bui.Widget | None = None,
 23    ):
 24        # pylint: disable=too-many-statements
 25        # pylint: disable=too-many-locals
 26        # pylint: disable=cyclic-import
 27        from bauiv1lib.popup import PopupMenu
 28        from bauiv1lib.config import ConfigNumberEdit
 29
 30        assert bui.app.classic is not None
 31        music = bui.app.classic.music
 32
 33        self._r = 'audioSettingsWindow'
 34
 35        spacing = 50.0
 36        width = 460.0
 37        height = 210.0
 38
 39        # Update: hard-coding head-relative audio to true now,
 40        # so not showing options.
 41        # show_vr_head_relative_audio = True if bui.app.vr_mode else False
 42        show_vr_head_relative_audio = False
 43
 44        if show_vr_head_relative_audio:
 45            height += 70
 46
 47        show_soundtracks = False
 48        if music.have_music_player():
 49            show_soundtracks = True
 50            height += spacing * 2.0
 51
 52        uiscale = bui.app.ui_v1.uiscale
 53        base_scale = (
 54            2.05
 55            if uiscale is bui.UIScale.SMALL
 56            else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
 57        )
 58        popup_menu_scale = base_scale * 1.2
 59
 60        super().__init__(
 61            root_widget=bui.containerwidget(
 62                size=(width, height),
 63                scale=base_scale,
 64                stack_offset=(
 65                    (0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
 66                ),
 67                toolbar_visibility=(
 68                    None if uiscale is bui.UIScale.SMALL else 'menu_full'
 69                ),
 70            ),
 71            transition=transition,
 72            origin_widget=origin_widget,
 73        )
 74
 75        self._back_button = back_button = btn = bui.buttonwidget(
 76            parent=self._root_widget,
 77            position=(35, height - 55),
 78            size=(120, 60),
 79            scale=0.8,
 80            text_scale=1.2,
 81            label=bui.Lstr(resource='backText'),
 82            button_type='back',
 83            on_activate_call=self.main_window_back,
 84            autoselect=True,
 85        )
 86        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
 87        v = height - 60
 88        v -= spacing * 1.0
 89        bui.textwidget(
 90            parent=self._root_widget,
 91            position=(width * 0.5, height - 32),
 92            size=(0, 0),
 93            text=bui.Lstr(resource=f'{self._r}.titleText'),
 94            color=bui.app.ui_v1.title_color,
 95            maxwidth=180,
 96            h_align='center',
 97            v_align='center',
 98        )
 99
100        bui.buttonwidget(
101            edit=self._back_button,
102            button_type='backSmall',
103            size=(60, 60),
104            label=bui.charstr(bui.SpecialChar.BACK),
105        )
106
107        self._sound_volume_numedit = svne = ConfigNumberEdit(
108            parent=self._root_widget,
109            position=(40, v),
110            xoffset=10,
111            configkey='Sound Volume',
112            displayname=bui.Lstr(resource=f'{self._r}.soundVolumeText'),
113            minval=0.0,
114            maxval=1.0,
115            increment=0.05,
116            as_percent=True,
117        )
118        bui.widget(
119            edit=svne.plusbutton,
120            right_widget=bui.get_special_widget('squad_button'),
121        )
122        v -= spacing
123        self._music_volume_numedit = ConfigNumberEdit(
124            parent=self._root_widget,
125            position=(40, v),
126            xoffset=10,
127            configkey='Music Volume',
128            displayname=bui.Lstr(resource=f'{self._r}.musicVolumeText'),
129            minval=0.0,
130            maxval=1.0,
131            increment=0.05,
132            callback=music.music_volume_changed,
133            changesound=False,
134            as_percent=True,
135        )
136
137        v -= 0.5 * spacing
138
139        self._vr_head_relative_audio_button: bui.Widget | None
140        if show_vr_head_relative_audio:
141            v -= 40
142            bui.textwidget(
143                parent=self._root_widget,
144                position=(40, v + 24),
145                size=(0, 0),
146                text=bui.Lstr(resource=f'{self._r}.headRelativeVRAudioText'),
147                color=(0.8, 0.8, 0.8),
148                maxwidth=230,
149                h_align='left',
150                v_align='center',
151            )
152
153            popup = PopupMenu(
154                parent=self._root_widget,
155                position=(290, v),
156                width=120,
157                button_size=(135, 50),
158                scale=popup_menu_scale,
159                choices=['Auto', 'On', 'Off'],
160                choices_display=[
161                    bui.Lstr(resource='autoText'),
162                    bui.Lstr(resource='onText'),
163                    bui.Lstr(resource='offText'),
164                ],
165                current_choice=bui.app.config.resolve('VR Head Relative Audio'),
166                on_value_change_call=self._set_vr_head_relative_audio,
167            )
168            self._vr_head_relative_audio_button = popup.get_button()
169            bui.textwidget(
170                parent=self._root_widget,
171                position=(width * 0.5, v - 11),
172                size=(0, 0),
173                text=bui.Lstr(
174                    resource=f'{self._r}.headRelativeVRAudioInfoText'
175                ),
176                scale=0.5,
177                color=(0.7, 0.8, 0.7),
178                maxwidth=400,
179                flatness=1.0,
180                h_align='center',
181                v_align='center',
182            )
183            v -= 30
184        else:
185            self._vr_head_relative_audio_button = None
186
187        self._soundtrack_button: bui.Widget | None
188        if show_soundtracks:
189            v -= 1.2 * spacing
190            self._soundtrack_button = bui.buttonwidget(
191                parent=self._root_widget,
192                position=((width - 310) / 2, v),
193                size=(310, 50),
194                autoselect=True,
195                label=bui.Lstr(resource=f'{self._r}.soundtrackButtonText'),
196                on_activate_call=self._do_soundtracks,
197            )
198            v -= spacing * 0.5
199            bui.textwidget(
200                parent=self._root_widget,
201                position=(0, v),
202                size=(width, 20),
203                text=bui.Lstr(resource=f'{self._r}.soundtrackDescriptionText'),
204                flatness=1.0,
205                h_align='center',
206                scale=0.5,
207                color=(0.7, 0.8, 0.7, 1.0),
208                maxwidth=400,
209            )
210        else:
211            self._soundtrack_button = None
212
213        # Tweak a few navigation bits.
214        try:
215            bui.widget(edit=back_button, down_widget=svne.minusbutton)
216        except Exception:
217            logging.exception('Error wiring AudioSettingsWindow.')
218
219        self._restore_state()
220
221    @override
222    def get_main_window_state(self) -> bui.MainWindowState:
223        # Support recreating our window for back/refresh purposes.
224        cls = type(self)
225        return bui.BasicMainWindowState(
226            create_call=lambda transition, origin_widget: cls(
227                transition=transition, origin_widget=origin_widget
228            )
229        )
230
231    @override
232    def on_main_window_close(self) -> None:
233        self._save_state()
234
235    def _set_vr_head_relative_audio(self, val: str) -> None:
236        cfg = bui.app.config
237        cfg['VR Head Relative Audio'] = val
238        cfg.apply_and_commit()
239
240    def _do_soundtracks(self) -> None:
241        # pylint: disable=cyclic-import
242        from bauiv1lib.soundtrack.browser import SoundtrackBrowserWindow
243
244        # no-op if we're not in control.
245        if not self.main_window_has_control():
246            return
247
248        # We require disk access for soundtracks; request it if we don't
249        # have it.
250        if not bui.have_permission(bui.Permission.STORAGE):
251            bui.getsound('ding').play()
252            bui.screenmessage(
253                bui.Lstr(resource='storagePermissionAccessText'),
254                color=(0.5, 1, 0.5),
255            )
256            bui.apptimer(
257                1.0, bui.Call(bui.request_permission, bui.Permission.STORAGE)
258            )
259            return
260
261        self.main_window_replace(
262            SoundtrackBrowserWindow(origin_widget=self._soundtrack_button)
263        )
264
265    def _save_state(self) -> None:
266        try:
267            sel = self._root_widget.get_selected_child()
268            if sel == self._sound_volume_numedit.minusbutton:
269                sel_name = 'SoundMinus'
270            elif sel == self._sound_volume_numedit.plusbutton:
271                sel_name = 'SoundPlus'
272            elif sel == self._music_volume_numedit.minusbutton:
273                sel_name = 'MusicMinus'
274            elif sel == self._music_volume_numedit.plusbutton:
275                sel_name = 'MusicPlus'
276            elif sel == self._soundtrack_button:
277                sel_name = 'Soundtrack'
278            elif sel == self._back_button:
279                sel_name = 'Back'
280            elif sel == self._vr_head_relative_audio_button:
281                sel_name = 'VRHeadRelative'
282            else:
283                raise ValueError(f'unrecognized selection \'{sel}\'')
284            assert bui.app.classic is not None
285            bui.app.ui_v1.window_states[type(self)] = sel_name
286        except Exception:
287            logging.exception('Error saving state for %s.', self)
288
289    def _restore_state(self) -> None:
290        try:
291            assert bui.app.classic is not None
292            sel_name = bui.app.ui_v1.window_states.get(type(self))
293            sel: bui.Widget | None
294            if sel_name == 'SoundMinus':
295                sel = self._sound_volume_numedit.minusbutton
296            elif sel_name == 'SoundPlus':
297                sel = self._sound_volume_numedit.plusbutton
298            elif sel_name == 'MusicMinus':
299                sel = self._music_volume_numedit.minusbutton
300            elif sel_name == 'MusicPlus':
301                sel = self._music_volume_numedit.plusbutton
302            elif sel_name == 'VRHeadRelative':
303                sel = self._vr_head_relative_audio_button
304            elif sel_name == 'Soundtrack':
305                sel = self._soundtrack_button
306            elif sel_name == 'Back':
307                sel = self._back_button
308            else:
309                sel = self._back_button
310            if sel:
311                bui.containerwidget(edit=self._root_widget, selected_child=sel)
312        except Exception:
313            logging.exception('Error restoring state for %s.', self)
class AudioSettingsWindow(bauiv1._uitypes.MainWindow):
 17class AudioSettingsWindow(bui.MainWindow):
 18    """Window for editing audio settings."""
 19
 20    def __init__(
 21        self,
 22        transition: str | None = 'in_right',
 23        origin_widget: bui.Widget | None = None,
 24    ):
 25        # pylint: disable=too-many-statements
 26        # pylint: disable=too-many-locals
 27        # pylint: disable=cyclic-import
 28        from bauiv1lib.popup import PopupMenu
 29        from bauiv1lib.config import ConfigNumberEdit
 30
 31        assert bui.app.classic is not None
 32        music = bui.app.classic.music
 33
 34        self._r = 'audioSettingsWindow'
 35
 36        spacing = 50.0
 37        width = 460.0
 38        height = 210.0
 39
 40        # Update: hard-coding head-relative audio to true now,
 41        # so not showing options.
 42        # show_vr_head_relative_audio = True if bui.app.vr_mode else False
 43        show_vr_head_relative_audio = False
 44
 45        if show_vr_head_relative_audio:
 46            height += 70
 47
 48        show_soundtracks = False
 49        if music.have_music_player():
 50            show_soundtracks = True
 51            height += spacing * 2.0
 52
 53        uiscale = bui.app.ui_v1.uiscale
 54        base_scale = (
 55            2.05
 56            if uiscale is bui.UIScale.SMALL
 57            else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
 58        )
 59        popup_menu_scale = base_scale * 1.2
 60
 61        super().__init__(
 62            root_widget=bui.containerwidget(
 63                size=(width, height),
 64                scale=base_scale,
 65                stack_offset=(
 66                    (0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
 67                ),
 68                toolbar_visibility=(
 69                    None if uiscale is bui.UIScale.SMALL else 'menu_full'
 70                ),
 71            ),
 72            transition=transition,
 73            origin_widget=origin_widget,
 74        )
 75
 76        self._back_button = back_button = btn = bui.buttonwidget(
 77            parent=self._root_widget,
 78            position=(35, height - 55),
 79            size=(120, 60),
 80            scale=0.8,
 81            text_scale=1.2,
 82            label=bui.Lstr(resource='backText'),
 83            button_type='back',
 84            on_activate_call=self.main_window_back,
 85            autoselect=True,
 86        )
 87        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
 88        v = height - 60
 89        v -= spacing * 1.0
 90        bui.textwidget(
 91            parent=self._root_widget,
 92            position=(width * 0.5, height - 32),
 93            size=(0, 0),
 94            text=bui.Lstr(resource=f'{self._r}.titleText'),
 95            color=bui.app.ui_v1.title_color,
 96            maxwidth=180,
 97            h_align='center',
 98            v_align='center',
 99        )
100
101        bui.buttonwidget(
102            edit=self._back_button,
103            button_type='backSmall',
104            size=(60, 60),
105            label=bui.charstr(bui.SpecialChar.BACK),
106        )
107
108        self._sound_volume_numedit = svne = ConfigNumberEdit(
109            parent=self._root_widget,
110            position=(40, v),
111            xoffset=10,
112            configkey='Sound Volume',
113            displayname=bui.Lstr(resource=f'{self._r}.soundVolumeText'),
114            minval=0.0,
115            maxval=1.0,
116            increment=0.05,
117            as_percent=True,
118        )
119        bui.widget(
120            edit=svne.plusbutton,
121            right_widget=bui.get_special_widget('squad_button'),
122        )
123        v -= spacing
124        self._music_volume_numedit = ConfigNumberEdit(
125            parent=self._root_widget,
126            position=(40, v),
127            xoffset=10,
128            configkey='Music Volume',
129            displayname=bui.Lstr(resource=f'{self._r}.musicVolumeText'),
130            minval=0.0,
131            maxval=1.0,
132            increment=0.05,
133            callback=music.music_volume_changed,
134            changesound=False,
135            as_percent=True,
136        )
137
138        v -= 0.5 * spacing
139
140        self._vr_head_relative_audio_button: bui.Widget | None
141        if show_vr_head_relative_audio:
142            v -= 40
143            bui.textwidget(
144                parent=self._root_widget,
145                position=(40, v + 24),
146                size=(0, 0),
147                text=bui.Lstr(resource=f'{self._r}.headRelativeVRAudioText'),
148                color=(0.8, 0.8, 0.8),
149                maxwidth=230,
150                h_align='left',
151                v_align='center',
152            )
153
154            popup = PopupMenu(
155                parent=self._root_widget,
156                position=(290, v),
157                width=120,
158                button_size=(135, 50),
159                scale=popup_menu_scale,
160                choices=['Auto', 'On', 'Off'],
161                choices_display=[
162                    bui.Lstr(resource='autoText'),
163                    bui.Lstr(resource='onText'),
164                    bui.Lstr(resource='offText'),
165                ],
166                current_choice=bui.app.config.resolve('VR Head Relative Audio'),
167                on_value_change_call=self._set_vr_head_relative_audio,
168            )
169            self._vr_head_relative_audio_button = popup.get_button()
170            bui.textwidget(
171                parent=self._root_widget,
172                position=(width * 0.5, v - 11),
173                size=(0, 0),
174                text=bui.Lstr(
175                    resource=f'{self._r}.headRelativeVRAudioInfoText'
176                ),
177                scale=0.5,
178                color=(0.7, 0.8, 0.7),
179                maxwidth=400,
180                flatness=1.0,
181                h_align='center',
182                v_align='center',
183            )
184            v -= 30
185        else:
186            self._vr_head_relative_audio_button = None
187
188        self._soundtrack_button: bui.Widget | None
189        if show_soundtracks:
190            v -= 1.2 * spacing
191            self._soundtrack_button = bui.buttonwidget(
192                parent=self._root_widget,
193                position=((width - 310) / 2, v),
194                size=(310, 50),
195                autoselect=True,
196                label=bui.Lstr(resource=f'{self._r}.soundtrackButtonText'),
197                on_activate_call=self._do_soundtracks,
198            )
199            v -= spacing * 0.5
200            bui.textwidget(
201                parent=self._root_widget,
202                position=(0, v),
203                size=(width, 20),
204                text=bui.Lstr(resource=f'{self._r}.soundtrackDescriptionText'),
205                flatness=1.0,
206                h_align='center',
207                scale=0.5,
208                color=(0.7, 0.8, 0.7, 1.0),
209                maxwidth=400,
210            )
211        else:
212            self._soundtrack_button = None
213
214        # Tweak a few navigation bits.
215        try:
216            bui.widget(edit=back_button, down_widget=svne.minusbutton)
217        except Exception:
218            logging.exception('Error wiring AudioSettingsWindow.')
219
220        self._restore_state()
221
222    @override
223    def get_main_window_state(self) -> bui.MainWindowState:
224        # Support recreating our window for back/refresh purposes.
225        cls = type(self)
226        return bui.BasicMainWindowState(
227            create_call=lambda transition, origin_widget: cls(
228                transition=transition, origin_widget=origin_widget
229            )
230        )
231
232    @override
233    def on_main_window_close(self) -> None:
234        self._save_state()
235
236    def _set_vr_head_relative_audio(self, val: str) -> None:
237        cfg = bui.app.config
238        cfg['VR Head Relative Audio'] = val
239        cfg.apply_and_commit()
240
241    def _do_soundtracks(self) -> None:
242        # pylint: disable=cyclic-import
243        from bauiv1lib.soundtrack.browser import SoundtrackBrowserWindow
244
245        # no-op if we're not in control.
246        if not self.main_window_has_control():
247            return
248
249        # We require disk access for soundtracks; request it if we don't
250        # have it.
251        if not bui.have_permission(bui.Permission.STORAGE):
252            bui.getsound('ding').play()
253            bui.screenmessage(
254                bui.Lstr(resource='storagePermissionAccessText'),
255                color=(0.5, 1, 0.5),
256            )
257            bui.apptimer(
258                1.0, bui.Call(bui.request_permission, bui.Permission.STORAGE)
259            )
260            return
261
262        self.main_window_replace(
263            SoundtrackBrowserWindow(origin_widget=self._soundtrack_button)
264        )
265
266    def _save_state(self) -> None:
267        try:
268            sel = self._root_widget.get_selected_child()
269            if sel == self._sound_volume_numedit.minusbutton:
270                sel_name = 'SoundMinus'
271            elif sel == self._sound_volume_numedit.plusbutton:
272                sel_name = 'SoundPlus'
273            elif sel == self._music_volume_numedit.minusbutton:
274                sel_name = 'MusicMinus'
275            elif sel == self._music_volume_numedit.plusbutton:
276                sel_name = 'MusicPlus'
277            elif sel == self._soundtrack_button:
278                sel_name = 'Soundtrack'
279            elif sel == self._back_button:
280                sel_name = 'Back'
281            elif sel == self._vr_head_relative_audio_button:
282                sel_name = 'VRHeadRelative'
283            else:
284                raise ValueError(f'unrecognized selection \'{sel}\'')
285            assert bui.app.classic is not None
286            bui.app.ui_v1.window_states[type(self)] = sel_name
287        except Exception:
288            logging.exception('Error saving state for %s.', self)
289
290    def _restore_state(self) -> None:
291        try:
292            assert bui.app.classic is not None
293            sel_name = bui.app.ui_v1.window_states.get(type(self))
294            sel: bui.Widget | None
295            if sel_name == 'SoundMinus':
296                sel = self._sound_volume_numedit.minusbutton
297            elif sel_name == 'SoundPlus':
298                sel = self._sound_volume_numedit.plusbutton
299            elif sel_name == 'MusicMinus':
300                sel = self._music_volume_numedit.minusbutton
301            elif sel_name == 'MusicPlus':
302                sel = self._music_volume_numedit.plusbutton
303            elif sel_name == 'VRHeadRelative':
304                sel = self._vr_head_relative_audio_button
305            elif sel_name == 'Soundtrack':
306                sel = self._soundtrack_button
307            elif sel_name == 'Back':
308                sel = self._back_button
309            else:
310                sel = self._back_button
311            if sel:
312                bui.containerwidget(edit=self._root_widget, selected_child=sel)
313        except Exception:
314            logging.exception('Error restoring state for %s.', self)

Window for editing audio settings.

AudioSettingsWindow( transition: str | None = 'in_right', origin_widget: _bauiv1.Widget | None = None)
 20    def __init__(
 21        self,
 22        transition: str | None = 'in_right',
 23        origin_widget: bui.Widget | None = None,
 24    ):
 25        # pylint: disable=too-many-statements
 26        # pylint: disable=too-many-locals
 27        # pylint: disable=cyclic-import
 28        from bauiv1lib.popup import PopupMenu
 29        from bauiv1lib.config import ConfigNumberEdit
 30
 31        assert bui.app.classic is not None
 32        music = bui.app.classic.music
 33
 34        self._r = 'audioSettingsWindow'
 35
 36        spacing = 50.0
 37        width = 460.0
 38        height = 210.0
 39
 40        # Update: hard-coding head-relative audio to true now,
 41        # so not showing options.
 42        # show_vr_head_relative_audio = True if bui.app.vr_mode else False
 43        show_vr_head_relative_audio = False
 44
 45        if show_vr_head_relative_audio:
 46            height += 70
 47
 48        show_soundtracks = False
 49        if music.have_music_player():
 50            show_soundtracks = True
 51            height += spacing * 2.0
 52
 53        uiscale = bui.app.ui_v1.uiscale
 54        base_scale = (
 55            2.05
 56            if uiscale is bui.UIScale.SMALL
 57            else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
 58        )
 59        popup_menu_scale = base_scale * 1.2
 60
 61        super().__init__(
 62            root_widget=bui.containerwidget(
 63                size=(width, height),
 64                scale=base_scale,
 65                stack_offset=(
 66                    (0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
 67                ),
 68                toolbar_visibility=(
 69                    None if uiscale is bui.UIScale.SMALL else 'menu_full'
 70                ),
 71            ),
 72            transition=transition,
 73            origin_widget=origin_widget,
 74        )
 75
 76        self._back_button = back_button = btn = bui.buttonwidget(
 77            parent=self._root_widget,
 78            position=(35, height - 55),
 79            size=(120, 60),
 80            scale=0.8,
 81            text_scale=1.2,
 82            label=bui.Lstr(resource='backText'),
 83            button_type='back',
 84            on_activate_call=self.main_window_back,
 85            autoselect=True,
 86        )
 87        bui.containerwidget(edit=self._root_widget, cancel_button=btn)
 88        v = height - 60
 89        v -= spacing * 1.0
 90        bui.textwidget(
 91            parent=self._root_widget,
 92            position=(width * 0.5, height - 32),
 93            size=(0, 0),
 94            text=bui.Lstr(resource=f'{self._r}.titleText'),
 95            color=bui.app.ui_v1.title_color,
 96            maxwidth=180,
 97            h_align='center',
 98            v_align='center',
 99        )
100
101        bui.buttonwidget(
102            edit=self._back_button,
103            button_type='backSmall',
104            size=(60, 60),
105            label=bui.charstr(bui.SpecialChar.BACK),
106        )
107
108        self._sound_volume_numedit = svne = ConfigNumberEdit(
109            parent=self._root_widget,
110            position=(40, v),
111            xoffset=10,
112            configkey='Sound Volume',
113            displayname=bui.Lstr(resource=f'{self._r}.soundVolumeText'),
114            minval=0.0,
115            maxval=1.0,
116            increment=0.05,
117            as_percent=True,
118        )
119        bui.widget(
120            edit=svne.plusbutton,
121            right_widget=bui.get_special_widget('squad_button'),
122        )
123        v -= spacing
124        self._music_volume_numedit = ConfigNumberEdit(
125            parent=self._root_widget,
126            position=(40, v),
127            xoffset=10,
128            configkey='Music Volume',
129            displayname=bui.Lstr(resource=f'{self._r}.musicVolumeText'),
130            minval=0.0,
131            maxval=1.0,
132            increment=0.05,
133            callback=music.music_volume_changed,
134            changesound=False,
135            as_percent=True,
136        )
137
138        v -= 0.5 * spacing
139
140        self._vr_head_relative_audio_button: bui.Widget | None
141        if show_vr_head_relative_audio:
142            v -= 40
143            bui.textwidget(
144                parent=self._root_widget,
145                position=(40, v + 24),
146                size=(0, 0),
147                text=bui.Lstr(resource=f'{self._r}.headRelativeVRAudioText'),
148                color=(0.8, 0.8, 0.8),
149                maxwidth=230,
150                h_align='left',
151                v_align='center',
152            )
153
154            popup = PopupMenu(
155                parent=self._root_widget,
156                position=(290, v),
157                width=120,
158                button_size=(135, 50),
159                scale=popup_menu_scale,
160                choices=['Auto', 'On', 'Off'],
161                choices_display=[
162                    bui.Lstr(resource='autoText'),
163                    bui.Lstr(resource='onText'),
164                    bui.Lstr(resource='offText'),
165                ],
166                current_choice=bui.app.config.resolve('VR Head Relative Audio'),
167                on_value_change_call=self._set_vr_head_relative_audio,
168            )
169            self._vr_head_relative_audio_button = popup.get_button()
170            bui.textwidget(
171                parent=self._root_widget,
172                position=(width * 0.5, v - 11),
173                size=(0, 0),
174                text=bui.Lstr(
175                    resource=f'{self._r}.headRelativeVRAudioInfoText'
176                ),
177                scale=0.5,
178                color=(0.7, 0.8, 0.7),
179                maxwidth=400,
180                flatness=1.0,
181                h_align='center',
182                v_align='center',
183            )
184            v -= 30
185        else:
186            self._vr_head_relative_audio_button = None
187
188        self._soundtrack_button: bui.Widget | None
189        if show_soundtracks:
190            v -= 1.2 * spacing
191            self._soundtrack_button = bui.buttonwidget(
192                parent=self._root_widget,
193                position=((width - 310) / 2, v),
194                size=(310, 50),
195                autoselect=True,
196                label=bui.Lstr(resource=f'{self._r}.soundtrackButtonText'),
197                on_activate_call=self._do_soundtracks,
198            )
199            v -= spacing * 0.5
200            bui.textwidget(
201                parent=self._root_widget,
202                position=(0, v),
203                size=(width, 20),
204                text=bui.Lstr(resource=f'{self._r}.soundtrackDescriptionText'),
205                flatness=1.0,
206                h_align='center',
207                scale=0.5,
208                color=(0.7, 0.8, 0.7, 1.0),
209                maxwidth=400,
210            )
211        else:
212            self._soundtrack_button = None
213
214        # Tweak a few navigation bits.
215        try:
216            bui.widget(edit=back_button, down_widget=svne.minusbutton)
217        except Exception:
218            logging.exception('Error wiring AudioSettingsWindow.')
219
220        self._restore_state()

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:
222    @override
223    def get_main_window_state(self) -> bui.MainWindowState:
224        # Support recreating our window for back/refresh purposes.
225        cls = type(self)
226        return bui.BasicMainWindowState(
227            create_call=lambda transition, origin_widget: cls(
228                transition=transition, origin_widget=origin_widget
229            )
230        )

Return a WindowState to recreate this window, if supported.

@override
def on_main_window_close(self) -> None:
232    @override
233    def on_main_window_close(self) -> None:
234        self._save_state()

Called before transitioning out a main window.

A good opportunity to save window state/etc.