bauiv1lib.settings.allsettings
UI for top level settings categories.
1# Released under the MIT License. See LICENSE for details. 2# 3"""UI for top level settings categories.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING, override 8import logging 9 10import bauiv1 as bui 11 12if TYPE_CHECKING: 13 from typing import Callable 14 15 16class AllSettingsWindow(bui.MainWindow): 17 """Window for selecting a settings category.""" 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-locals 25 26 # Preload some modules we use in a background thread so we won't 27 # have a visual hitch when the user taps them. 28 bui.app.threadpool.submit_no_wait(self._preload_modules) 29 30 bui.set_analytics_screen('Settings Window') 31 assert bui.app.classic is not None 32 uiscale = bui.app.ui_v1.uiscale 33 width = 1000 if uiscale is bui.UIScale.SMALL else 900 34 height = 800 if uiscale is bui.UIScale.SMALL else 450 35 self._r = 'settingsWindow' 36 37 uiscale = bui.app.ui_v1.uiscale 38 39 # Do some fancy math to fill all available screen area up to the 40 # size of our backing container. This lets us fit to the exact 41 # screen shape at small ui scale. 42 screensize = bui.get_virtual_screen_size() 43 safesize = bui.get_virtual_safe_area_size() 44 45 # We're a generally widescreen shaped window, so bump our 46 # overall scale up a bit when screen width is wider than safe 47 # bounds to take advantage of the extra space. 48 smallscale = min(2.0, 1.5 * screensize[0] / safesize[0]) 49 50 scale = ( 51 smallscale 52 if uiscale is bui.UIScale.SMALL 53 else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.8 54 ) 55 # Calc screen size in our local container space and clamp to a 56 # bit smaller than our container size. 57 target_height = min(height - 70, screensize[1] / scale) 58 59 # To get top/left coords, go to the center of our window and 60 # offset by half the width/height of our target area. 61 yoffs = 0.5 * height + 0.5 * target_height + 30.0 62 63 # scroll_width = target_width 64 # scroll_height = target_height - 25 65 # scroll_bottom = yoffs - 54 - scroll_height 66 67 super().__init__( 68 root_widget=bui.containerwidget( 69 size=(width, height), 70 toolbar_visibility=( 71 'menu_minimal' 72 if uiscale is bui.UIScale.SMALL 73 else 'menu_full' 74 ), 75 scale=scale, 76 ), 77 transition=transition, 78 origin_widget=origin_widget, 79 # We're affected by screen size only at small ui-scale. 80 refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, 81 ) 82 83 if uiscale is bui.UIScale.SMALL: 84 self._back_button = None 85 bui.containerwidget( 86 edit=self._root_widget, on_cancel_call=self.main_window_back 87 ) 88 else: 89 self._back_button = btn = bui.buttonwidget( 90 parent=self._root_widget, 91 autoselect=True, 92 position=(50, yoffs - 80.0), 93 size=(70, 70), 94 scale=0.8, 95 text_scale=1.2, 96 label=bui.charstr(bui.SpecialChar.BACK), 97 button_type='backSmall', 98 on_activate_call=self.main_window_back, 99 ) 100 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 101 102 bui.textwidget( 103 parent=self._root_widget, 104 position=(0, yoffs - (70 if uiscale is bui.UIScale.SMALL else 60)), 105 size=(width, 25), 106 text=bui.Lstr(resource=f'{self._r}.titleText'), 107 color=bui.app.ui_v1.title_color, 108 h_align='center', 109 v_align='center', 110 scale=1.1, 111 maxwidth=130, 112 ) 113 114 bwidth = 200 115 bheight = 230 116 margin = 1 117 all_buttons_width = 4.0 * bwidth + 3.0 * margin 118 119 x = width * 0.5 - all_buttons_width * 0.5 120 y = height * 0.5 - bheight * 0.5 - 20.0 121 122 def _button( 123 position: tuple[float, float], 124 label: bui.Lstr, 125 call: Callable[[], None], 126 texture: bui.Texture, 127 imgsize: float, 128 *, 129 color: tuple[float, float, float] = (1.0, 1.0, 1.0), 130 imgoffs: tuple[float, float] = (0.0, 0.0), 131 ) -> bui.Widget: 132 x, y = position 133 btn = bui.buttonwidget( 134 parent=self._root_widget, 135 autoselect=True, 136 position=(x, y), 137 size=(bwidth, bheight), 138 button_type='square', 139 label='', 140 on_activate_call=call, 141 ) 142 bui.textwidget( 143 parent=self._root_widget, 144 text=label, 145 position=(x + bwidth * 0.5, y + bheight * 0.25), 146 maxwidth=bwidth * 0.7, 147 size=(0, 0), 148 h_align='center', 149 v_align='center', 150 draw_controller=btn, 151 color=(0.7, 0.9, 0.7, 1.0), 152 ) 153 bui.imagewidget( 154 parent=self._root_widget, 155 position=( 156 x + bwidth * 0.5 - imgsize * 0.5 + imgoffs[0], 157 y + bheight * 0.56 - imgsize * 0.5 + imgoffs[1], 158 ), 159 size=(imgsize, imgsize), 160 texture=texture, 161 draw_controller=btn, 162 color=color, 163 ) 164 return btn 165 166 self._controllers_button = _button( 167 position=(x, y), 168 label=bui.Lstr(resource=f'{self._r}.controllersText'), 169 call=self._do_controllers, 170 texture=bui.gettexture('controllerIcon'), 171 imgsize=150, 172 imgoffs=(-2.0, 2.0), 173 ) 174 x += bwidth + margin 175 176 self._graphics_button = _button( 177 position=(x, y), 178 label=bui.Lstr(resource=f'{self._r}.graphicsText'), 179 call=self._do_graphics, 180 texture=bui.gettexture('graphicsIcon'), 181 imgsize=135, 182 imgoffs=(0, 4.0), 183 ) 184 x += bwidth + margin 185 186 self._audio_button = _button( 187 position=(x, y), 188 label=bui.Lstr(resource=f'{self._r}.audioText'), 189 call=self._do_audio, 190 texture=bui.gettexture('audioIcon'), 191 imgsize=150, 192 color=(1, 1, 0), 193 ) 194 x += bwidth + margin 195 196 self._advanced_button = _button( 197 position=(x, y), 198 label=bui.Lstr(resource=f'{self._r}.advancedText'), 199 call=self._do_advanced, 200 texture=bui.gettexture('advancedIcon'), 201 imgsize=150, 202 color=(0.8, 0.95, 1), 203 imgoffs=(0, 5.0), 204 ) 205 206 # Hmm; we're now wide enough that being limited to pressing up 207 # might be ok. 208 if bool(False): 209 # Left from our leftmost button should go to back button. 210 if self._back_button is None: 211 bbtn = bui.get_special_widget('back_button') 212 bui.widget(edit=self._controllers_button, left_widget=bbtn) 213 214 # Right from our rightmost widget should go to squad button. 215 bui.widget( 216 edit=self._advanced_button, 217 right_widget=bui.get_special_widget('squad_button'), 218 ) 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 @staticmethod 237 def _preload_modules() -> None: 238 """Preload modules we use; avoids hitches (called in bg thread).""" 239 import bauiv1lib.mainmenu as _unused1 240 import bauiv1lib.settings.controls as _unused2 241 import bauiv1lib.settings.graphics as _unused3 242 import bauiv1lib.settings.audio as _unused4 243 import bauiv1lib.settings.advanced as _unused5 244 245 def _do_controllers(self) -> None: 246 # pylint: disable=cyclic-import 247 from bauiv1lib.settings.controls import ControlsSettingsWindow 248 249 # no-op if we're not in control. 250 if not self.main_window_has_control(): 251 return 252 253 self.main_window_replace( 254 ControlsSettingsWindow(origin_widget=self._controllers_button) 255 ) 256 257 def _do_graphics(self) -> None: 258 # pylint: disable=cyclic-import 259 from bauiv1lib.settings.graphics import GraphicsSettingsWindow 260 261 # no-op if we're not in control. 262 if not self.main_window_has_control(): 263 return 264 265 self.main_window_replace( 266 GraphicsSettingsWindow(origin_widget=self._graphics_button) 267 ) 268 269 def _do_audio(self) -> None: 270 # pylint: disable=cyclic-import 271 from bauiv1lib.settings.audio import AudioSettingsWindow 272 273 # no-op if we're not in control. 274 if not self.main_window_has_control(): 275 return 276 277 self.main_window_replace( 278 AudioSettingsWindow(origin_widget=self._audio_button) 279 ) 280 281 def _do_advanced(self) -> None: 282 # pylint: disable=cyclic-import 283 from bauiv1lib.settings.advanced import AdvancedSettingsWindow 284 285 # no-op if we're not in control. 286 if not self.main_window_has_control(): 287 return 288 289 self.main_window_replace( 290 AdvancedSettingsWindow(origin_widget=self._advanced_button) 291 ) 292 293 def _save_state(self) -> None: 294 try: 295 sel = self._root_widget.get_selected_child() 296 if sel == self._controllers_button: 297 sel_name = 'Controllers' 298 elif sel == self._graphics_button: 299 sel_name = 'Graphics' 300 elif sel == self._audio_button: 301 sel_name = 'Audio' 302 elif sel == self._advanced_button: 303 sel_name = 'Advanced' 304 elif sel == self._back_button: 305 sel_name = 'Back' 306 else: 307 raise ValueError(f'unrecognized selection \'{sel}\'') 308 assert bui.app.classic is not None 309 bui.app.ui_v1.window_states[type(self)] = {'sel_name': sel_name} 310 except Exception: 311 logging.exception('Error saving state for %s.', self) 312 313 def _restore_state(self) -> None: 314 try: 315 assert bui.app.classic is not None 316 sel_name = bui.app.ui_v1.window_states.get(type(self), {}).get( 317 'sel_name' 318 ) 319 sel: bui.Widget | None 320 if sel_name == 'Controllers': 321 sel = self._controllers_button 322 elif sel_name == 'Graphics': 323 sel = self._graphics_button 324 elif sel_name == 'Audio': 325 sel = self._audio_button 326 elif sel_name == 'Advanced': 327 sel = self._advanced_button 328 elif sel_name == 'Back': 329 sel = self._back_button 330 else: 331 sel = self._controllers_button 332 if sel is not None: 333 bui.containerwidget(edit=self._root_widget, selected_child=sel) 334 except Exception: 335 logging.exception('Error restoring state for %s.', self)
class
AllSettingsWindow(bauiv1._uitypes.MainWindow):
17class AllSettingsWindow(bui.MainWindow): 18 """Window for selecting a settings category.""" 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-locals 26 27 # Preload some modules we use in a background thread so we won't 28 # have a visual hitch when the user taps them. 29 bui.app.threadpool.submit_no_wait(self._preload_modules) 30 31 bui.set_analytics_screen('Settings Window') 32 assert bui.app.classic is not None 33 uiscale = bui.app.ui_v1.uiscale 34 width = 1000 if uiscale is bui.UIScale.SMALL else 900 35 height = 800 if uiscale is bui.UIScale.SMALL else 450 36 self._r = 'settingsWindow' 37 38 uiscale = bui.app.ui_v1.uiscale 39 40 # Do some fancy math to fill all available screen area up to the 41 # size of our backing container. This lets us fit to the exact 42 # screen shape at small ui scale. 43 screensize = bui.get_virtual_screen_size() 44 safesize = bui.get_virtual_safe_area_size() 45 46 # We're a generally widescreen shaped window, so bump our 47 # overall scale up a bit when screen width is wider than safe 48 # bounds to take advantage of the extra space. 49 smallscale = min(2.0, 1.5 * screensize[0] / safesize[0]) 50 51 scale = ( 52 smallscale 53 if uiscale is bui.UIScale.SMALL 54 else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.8 55 ) 56 # Calc screen size in our local container space and clamp to a 57 # bit smaller than our container size. 58 target_height = min(height - 70, screensize[1] / scale) 59 60 # To get top/left coords, go to the center of our window and 61 # offset by half the width/height of our target area. 62 yoffs = 0.5 * height + 0.5 * target_height + 30.0 63 64 # scroll_width = target_width 65 # scroll_height = target_height - 25 66 # scroll_bottom = yoffs - 54 - scroll_height 67 68 super().__init__( 69 root_widget=bui.containerwidget( 70 size=(width, height), 71 toolbar_visibility=( 72 'menu_minimal' 73 if uiscale is bui.UIScale.SMALL 74 else 'menu_full' 75 ), 76 scale=scale, 77 ), 78 transition=transition, 79 origin_widget=origin_widget, 80 # We're affected by screen size only at small ui-scale. 81 refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, 82 ) 83 84 if uiscale is bui.UIScale.SMALL: 85 self._back_button = None 86 bui.containerwidget( 87 edit=self._root_widget, on_cancel_call=self.main_window_back 88 ) 89 else: 90 self._back_button = btn = bui.buttonwidget( 91 parent=self._root_widget, 92 autoselect=True, 93 position=(50, yoffs - 80.0), 94 size=(70, 70), 95 scale=0.8, 96 text_scale=1.2, 97 label=bui.charstr(bui.SpecialChar.BACK), 98 button_type='backSmall', 99 on_activate_call=self.main_window_back, 100 ) 101 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 102 103 bui.textwidget( 104 parent=self._root_widget, 105 position=(0, yoffs - (70 if uiscale is bui.UIScale.SMALL else 60)), 106 size=(width, 25), 107 text=bui.Lstr(resource=f'{self._r}.titleText'), 108 color=bui.app.ui_v1.title_color, 109 h_align='center', 110 v_align='center', 111 scale=1.1, 112 maxwidth=130, 113 ) 114 115 bwidth = 200 116 bheight = 230 117 margin = 1 118 all_buttons_width = 4.0 * bwidth + 3.0 * margin 119 120 x = width * 0.5 - all_buttons_width * 0.5 121 y = height * 0.5 - bheight * 0.5 - 20.0 122 123 def _button( 124 position: tuple[float, float], 125 label: bui.Lstr, 126 call: Callable[[], None], 127 texture: bui.Texture, 128 imgsize: float, 129 *, 130 color: tuple[float, float, float] = (1.0, 1.0, 1.0), 131 imgoffs: tuple[float, float] = (0.0, 0.0), 132 ) -> bui.Widget: 133 x, y = position 134 btn = bui.buttonwidget( 135 parent=self._root_widget, 136 autoselect=True, 137 position=(x, y), 138 size=(bwidth, bheight), 139 button_type='square', 140 label='', 141 on_activate_call=call, 142 ) 143 bui.textwidget( 144 parent=self._root_widget, 145 text=label, 146 position=(x + bwidth * 0.5, y + bheight * 0.25), 147 maxwidth=bwidth * 0.7, 148 size=(0, 0), 149 h_align='center', 150 v_align='center', 151 draw_controller=btn, 152 color=(0.7, 0.9, 0.7, 1.0), 153 ) 154 bui.imagewidget( 155 parent=self._root_widget, 156 position=( 157 x + bwidth * 0.5 - imgsize * 0.5 + imgoffs[0], 158 y + bheight * 0.56 - imgsize * 0.5 + imgoffs[1], 159 ), 160 size=(imgsize, imgsize), 161 texture=texture, 162 draw_controller=btn, 163 color=color, 164 ) 165 return btn 166 167 self._controllers_button = _button( 168 position=(x, y), 169 label=bui.Lstr(resource=f'{self._r}.controllersText'), 170 call=self._do_controllers, 171 texture=bui.gettexture('controllerIcon'), 172 imgsize=150, 173 imgoffs=(-2.0, 2.0), 174 ) 175 x += bwidth + margin 176 177 self._graphics_button = _button( 178 position=(x, y), 179 label=bui.Lstr(resource=f'{self._r}.graphicsText'), 180 call=self._do_graphics, 181 texture=bui.gettexture('graphicsIcon'), 182 imgsize=135, 183 imgoffs=(0, 4.0), 184 ) 185 x += bwidth + margin 186 187 self._audio_button = _button( 188 position=(x, y), 189 label=bui.Lstr(resource=f'{self._r}.audioText'), 190 call=self._do_audio, 191 texture=bui.gettexture('audioIcon'), 192 imgsize=150, 193 color=(1, 1, 0), 194 ) 195 x += bwidth + margin 196 197 self._advanced_button = _button( 198 position=(x, y), 199 label=bui.Lstr(resource=f'{self._r}.advancedText'), 200 call=self._do_advanced, 201 texture=bui.gettexture('advancedIcon'), 202 imgsize=150, 203 color=(0.8, 0.95, 1), 204 imgoffs=(0, 5.0), 205 ) 206 207 # Hmm; we're now wide enough that being limited to pressing up 208 # might be ok. 209 if bool(False): 210 # Left from our leftmost button should go to back button. 211 if self._back_button is None: 212 bbtn = bui.get_special_widget('back_button') 213 bui.widget(edit=self._controllers_button, left_widget=bbtn) 214 215 # Right from our rightmost widget should go to squad button. 216 bui.widget( 217 edit=self._advanced_button, 218 right_widget=bui.get_special_widget('squad_button'), 219 ) 220 221 self._restore_state() 222 223 @override 224 def get_main_window_state(self) -> bui.MainWindowState: 225 # Support recreating our window for back/refresh purposes. 226 cls = type(self) 227 return bui.BasicMainWindowState( 228 create_call=lambda transition, origin_widget: cls( 229 transition=transition, origin_widget=origin_widget 230 ) 231 ) 232 233 @override 234 def on_main_window_close(self) -> None: 235 self._save_state() 236 237 @staticmethod 238 def _preload_modules() -> None: 239 """Preload modules we use; avoids hitches (called in bg thread).""" 240 import bauiv1lib.mainmenu as _unused1 241 import bauiv1lib.settings.controls as _unused2 242 import bauiv1lib.settings.graphics as _unused3 243 import bauiv1lib.settings.audio as _unused4 244 import bauiv1lib.settings.advanced as _unused5 245 246 def _do_controllers(self) -> None: 247 # pylint: disable=cyclic-import 248 from bauiv1lib.settings.controls import ControlsSettingsWindow 249 250 # no-op if we're not in control. 251 if not self.main_window_has_control(): 252 return 253 254 self.main_window_replace( 255 ControlsSettingsWindow(origin_widget=self._controllers_button) 256 ) 257 258 def _do_graphics(self) -> None: 259 # pylint: disable=cyclic-import 260 from bauiv1lib.settings.graphics import GraphicsSettingsWindow 261 262 # no-op if we're not in control. 263 if not self.main_window_has_control(): 264 return 265 266 self.main_window_replace( 267 GraphicsSettingsWindow(origin_widget=self._graphics_button) 268 ) 269 270 def _do_audio(self) -> None: 271 # pylint: disable=cyclic-import 272 from bauiv1lib.settings.audio import AudioSettingsWindow 273 274 # no-op if we're not in control. 275 if not self.main_window_has_control(): 276 return 277 278 self.main_window_replace( 279 AudioSettingsWindow(origin_widget=self._audio_button) 280 ) 281 282 def _do_advanced(self) -> None: 283 # pylint: disable=cyclic-import 284 from bauiv1lib.settings.advanced import AdvancedSettingsWindow 285 286 # no-op if we're not in control. 287 if not self.main_window_has_control(): 288 return 289 290 self.main_window_replace( 291 AdvancedSettingsWindow(origin_widget=self._advanced_button) 292 ) 293 294 def _save_state(self) -> None: 295 try: 296 sel = self._root_widget.get_selected_child() 297 if sel == self._controllers_button: 298 sel_name = 'Controllers' 299 elif sel == self._graphics_button: 300 sel_name = 'Graphics' 301 elif sel == self._audio_button: 302 sel_name = 'Audio' 303 elif sel == self._advanced_button: 304 sel_name = 'Advanced' 305 elif sel == self._back_button: 306 sel_name = 'Back' 307 else: 308 raise ValueError(f'unrecognized selection \'{sel}\'') 309 assert bui.app.classic is not None 310 bui.app.ui_v1.window_states[type(self)] = {'sel_name': sel_name} 311 except Exception: 312 logging.exception('Error saving state for %s.', self) 313 314 def _restore_state(self) -> None: 315 try: 316 assert bui.app.classic is not None 317 sel_name = bui.app.ui_v1.window_states.get(type(self), {}).get( 318 'sel_name' 319 ) 320 sel: bui.Widget | None 321 if sel_name == 'Controllers': 322 sel = self._controllers_button 323 elif sel_name == 'Graphics': 324 sel = self._graphics_button 325 elif sel_name == 'Audio': 326 sel = self._audio_button 327 elif sel_name == 'Advanced': 328 sel = self._advanced_button 329 elif sel_name == 'Back': 330 sel = self._back_button 331 else: 332 sel = self._controllers_button 333 if sel is not None: 334 bui.containerwidget(edit=self._root_widget, selected_child=sel) 335 except Exception: 336 logging.exception('Error restoring state for %s.', self)
Window for selecting a settings category.
AllSettingsWindow( 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-locals 26 27 # Preload some modules we use in a background thread so we won't 28 # have a visual hitch when the user taps them. 29 bui.app.threadpool.submit_no_wait(self._preload_modules) 30 31 bui.set_analytics_screen('Settings Window') 32 assert bui.app.classic is not None 33 uiscale = bui.app.ui_v1.uiscale 34 width = 1000 if uiscale is bui.UIScale.SMALL else 900 35 height = 800 if uiscale is bui.UIScale.SMALL else 450 36 self._r = 'settingsWindow' 37 38 uiscale = bui.app.ui_v1.uiscale 39 40 # Do some fancy math to fill all available screen area up to the 41 # size of our backing container. This lets us fit to the exact 42 # screen shape at small ui scale. 43 screensize = bui.get_virtual_screen_size() 44 safesize = bui.get_virtual_safe_area_size() 45 46 # We're a generally widescreen shaped window, so bump our 47 # overall scale up a bit when screen width is wider than safe 48 # bounds to take advantage of the extra space. 49 smallscale = min(2.0, 1.5 * screensize[0] / safesize[0]) 50 51 scale = ( 52 smallscale 53 if uiscale is bui.UIScale.SMALL 54 else 1.1 if uiscale is bui.UIScale.MEDIUM else 0.8 55 ) 56 # Calc screen size in our local container space and clamp to a 57 # bit smaller than our container size. 58 target_height = min(height - 70, screensize[1] / scale) 59 60 # To get top/left coords, go to the center of our window and 61 # offset by half the width/height of our target area. 62 yoffs = 0.5 * height + 0.5 * target_height + 30.0 63 64 # scroll_width = target_width 65 # scroll_height = target_height - 25 66 # scroll_bottom = yoffs - 54 - scroll_height 67 68 super().__init__( 69 root_widget=bui.containerwidget( 70 size=(width, height), 71 toolbar_visibility=( 72 'menu_minimal' 73 if uiscale is bui.UIScale.SMALL 74 else 'menu_full' 75 ), 76 scale=scale, 77 ), 78 transition=transition, 79 origin_widget=origin_widget, 80 # We're affected by screen size only at small ui-scale. 81 refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL, 82 ) 83 84 if uiscale is bui.UIScale.SMALL: 85 self._back_button = None 86 bui.containerwidget( 87 edit=self._root_widget, on_cancel_call=self.main_window_back 88 ) 89 else: 90 self._back_button = btn = bui.buttonwidget( 91 parent=self._root_widget, 92 autoselect=True, 93 position=(50, yoffs - 80.0), 94 size=(70, 70), 95 scale=0.8, 96 text_scale=1.2, 97 label=bui.charstr(bui.SpecialChar.BACK), 98 button_type='backSmall', 99 on_activate_call=self.main_window_back, 100 ) 101 bui.containerwidget(edit=self._root_widget, cancel_button=btn) 102 103 bui.textwidget( 104 parent=self._root_widget, 105 position=(0, yoffs - (70 if uiscale is bui.UIScale.SMALL else 60)), 106 size=(width, 25), 107 text=bui.Lstr(resource=f'{self._r}.titleText'), 108 color=bui.app.ui_v1.title_color, 109 h_align='center', 110 v_align='center', 111 scale=1.1, 112 maxwidth=130, 113 ) 114 115 bwidth = 200 116 bheight = 230 117 margin = 1 118 all_buttons_width = 4.0 * bwidth + 3.0 * margin 119 120 x = width * 0.5 - all_buttons_width * 0.5 121 y = height * 0.5 - bheight * 0.5 - 20.0 122 123 def _button( 124 position: tuple[float, float], 125 label: bui.Lstr, 126 call: Callable[[], None], 127 texture: bui.Texture, 128 imgsize: float, 129 *, 130 color: tuple[float, float, float] = (1.0, 1.0, 1.0), 131 imgoffs: tuple[float, float] = (0.0, 0.0), 132 ) -> bui.Widget: 133 x, y = position 134 btn = bui.buttonwidget( 135 parent=self._root_widget, 136 autoselect=True, 137 position=(x, y), 138 size=(bwidth, bheight), 139 button_type='square', 140 label='', 141 on_activate_call=call, 142 ) 143 bui.textwidget( 144 parent=self._root_widget, 145 text=label, 146 position=(x + bwidth * 0.5, y + bheight * 0.25), 147 maxwidth=bwidth * 0.7, 148 size=(0, 0), 149 h_align='center', 150 v_align='center', 151 draw_controller=btn, 152 color=(0.7, 0.9, 0.7, 1.0), 153 ) 154 bui.imagewidget( 155 parent=self._root_widget, 156 position=( 157 x + bwidth * 0.5 - imgsize * 0.5 + imgoffs[0], 158 y + bheight * 0.56 - imgsize * 0.5 + imgoffs[1], 159 ), 160 size=(imgsize, imgsize), 161 texture=texture, 162 draw_controller=btn, 163 color=color, 164 ) 165 return btn 166 167 self._controllers_button = _button( 168 position=(x, y), 169 label=bui.Lstr(resource=f'{self._r}.controllersText'), 170 call=self._do_controllers, 171 texture=bui.gettexture('controllerIcon'), 172 imgsize=150, 173 imgoffs=(-2.0, 2.0), 174 ) 175 x += bwidth + margin 176 177 self._graphics_button = _button( 178 position=(x, y), 179 label=bui.Lstr(resource=f'{self._r}.graphicsText'), 180 call=self._do_graphics, 181 texture=bui.gettexture('graphicsIcon'), 182 imgsize=135, 183 imgoffs=(0, 4.0), 184 ) 185 x += bwidth + margin 186 187 self._audio_button = _button( 188 position=(x, y), 189 label=bui.Lstr(resource=f'{self._r}.audioText'), 190 call=self._do_audio, 191 texture=bui.gettexture('audioIcon'), 192 imgsize=150, 193 color=(1, 1, 0), 194 ) 195 x += bwidth + margin 196 197 self._advanced_button = _button( 198 position=(x, y), 199 label=bui.Lstr(resource=f'{self._r}.advancedText'), 200 call=self._do_advanced, 201 texture=bui.gettexture('advancedIcon'), 202 imgsize=150, 203 color=(0.8, 0.95, 1), 204 imgoffs=(0, 5.0), 205 ) 206 207 # Hmm; we're now wide enough that being limited to pressing up 208 # might be ok. 209 if bool(False): 210 # Left from our leftmost button should go to back button. 211 if self._back_button is None: 212 bbtn = bui.get_special_widget('back_button') 213 bui.widget(edit=self._controllers_button, left_widget=bbtn) 214 215 # Right from our rightmost widget should go to squad button. 216 bui.widget( 217 edit=self._advanced_button, 218 right_widget=bui.get_special_widget('squad_button'), 219 ) 220 221 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.
223 @override 224 def get_main_window_state(self) -> bui.MainWindowState: 225 # Support recreating our window for back/refresh purposes. 226 cls = type(self) 227 return bui.BasicMainWindowState( 228 create_call=lambda transition, origin_widget: cls( 229 transition=transition, origin_widget=origin_widget 230 ) 231 )
Return a WindowState to recreate this window, if supported.