def uicleanupcheck(obj: Any, widget: ba.Widget) -> None: """Add a check to ensure a widget-owning object gets cleaned up properly. Category: User Interface Functions This adds a check which will print an error message if the provided object still exists ~5 seconds after the provided ba.Widget dies. This is a good sanity check for any sort of object that wraps or controls a ba.Widget. For instance, a 'Window' class instance has no reason to still exist once its root container ba.Widget has fully transitioned out and been destroyed. Circular references or careless strong referencing can lead to such objects never getting destroyed, however, and this helps detect such cases to avoid memory leaks. """ if DEBUG_UI_CLEANUP_CHECKS: print(f'adding uicleanup to {obj}') if not isinstance(widget, _ba.Widget): raise TypeError('widget arg is not a ba.Widget') if bool(False): def foobar() -> None: """Just testing.""" if DEBUG_UI_CLEANUP_CHECKS: print('uicleanupcheck widget dying...') widget.add_delete_callback(foobar) _ba.app.ui.cleanupchecks.append( UICleanupCheck(obj=weakref.ref(obj), widget=widget, widget_death_time=None))
def __init__(self, origin_widget: ba.Widget, qr_tex: ba.Texture): position = origin_widget.get_screen_space_center() uiscale = ba.app.uiscale scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 450 self._height = 400 bg_color = (0.5, 0.4, 0.6) popup.PopupWindow.__init__(self, position=position, size=(self._width, self._height), scale=scale, bg_color=bg_color) self._cancel_button = ba.buttonwidget( parent=self.root_widget, position=(50, self._height - 30), size=(50, 50), scale=0.5, label='', color=bg_color, on_activate_call=self._on_cancel_press, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) ba.imagewidget(parent=self.root_widget, position=(self._width * 0.5 - 150, self._height * 0.5 - 150), size=(300, 300), texture=qr_tex)
def _show_account_info(self, account_id: str, textwidget: ba.Widget) -> None: from bastd.ui.account import viewer ba.playsound(ba.getsound('swish')) viewer.AccountViewerWindow( account_id=account_id, position=textwidget.get_screen_space_center())
def __init__(self, origin_widget: ba.Widget): uiscale = ba.app.ui.uiscale scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 570 self._height = 350 bg_color = (0.5, 0.4, 0.6) popup.PopupWindow.__init__( self, size=(self._width, self._height), toolbar_visibility='inherit', scale=scale, bg_color=bg_color, position=origin_widget.get_screen_space_center()) self._cancel_button = ba.buttonwidget( parent=self.root_widget, position=(50, self._height - 30), size=(50, 50), scale=0.5, label='', color=bg_color, on_activate_call=self._on_cancel_press, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2)
def on_account_press(self, account_id: Optional[str], origin_widget: ba.Widget) -> None: """A dude was clicked so we should show his account info.""" from bastd.ui.account import viewer if account_id is None: ba.playsound(ba.getsound('error')) return viewer.AccountViewerWindow( account_id=account_id, position=origin_widget.get_screen_space_center())
def _show_player_info(self, entry: Any, textwidget: ba.Widget) -> None: from bastd.ui.account.viewer import AccountViewerWindow # for the moment we only work if a single player-info is present.. if len(entry[2]) != 1: ba.playsound(ba.getsound('error')) return ba.playsound(ba.getsound('swish')) AccountViewerWindow(account_id=entry[2][0].get('a', None), profile_id=entry[2][0].get('p', None), position=textwidget.get_screen_space_center()) self._transition_out()
def __init__(self, account_id: str, origin_widget: ba.Widget): self._width = 550 self._height = 220 self._account_id = account_id self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() overlay_stack = _ba.get_special_widget('overlay_stack') uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), parent=overlay_stack, transition='in_scale', scale_origin_stack_offset=scale_origin, scale=(1.8 if uiscale is ba.UIScale.SMALL else 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=0.7, position=(40, self._height - 50), size=(50, 50), label='', on_activate_call=self.close, autoselect=True, color=(0.4, 0.4, 0.5), icon=ba.gettexture('crossOut'), iconscale=1.2) ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height * 0.64), size=(0, 0), color=(1, 1, 1, 0.8), scale=1.2, h_align='center', v_align='center', text=ba.Lstr(resource='reportThisPlayerReasonText'), maxwidth=self._width * 0.85) ba.buttonwidget(parent=self._root_widget, size=(235, 60), position=(20, 30), label=ba.Lstr(resource='reportThisPlayerLanguageText'), on_activate_call=self._on_language_press, autoselect=True) ba.buttonwidget(parent=self._root_widget, size=(235, 60), position=(self._width - 255, 30), label=ba.Lstr(resource='reportThisPlayerCheatingText'), on_activate_call=self._on_cheating_press, autoselect=True)
def _on_playlist_press(self, button: ba.Widget, playlist_name: str) -> None: # pylint: disable=cyclic-import from bastd.ui.playoptions import PlayOptionsWindow # Make sure the target playlist still exists. exists = (playlist_name == '__default__' or playlist_name in ba.app.config.get( self._config_name_full, {})) if not exists: return self._save_state() PlayOptionsWindow(sessiontype=self._sessiontype, scale_origin=button.get_screen_space_center(), playlist=playlist_name, delegate=self)
def _on_party_member_press(self, client_id: int, is_host: bool, widget: ba.Widget) -> None: # if we're the host, pop up 'kick' options for all non-host members if _ba.get_foreground_host_session() is not None: kick_str = ba.Lstr(resource='kickText') else: # kick-votes appeared in build 14248 if (_ba.get_connection_to_host_info().get('build_number', 0) < 14248): return kick_str = ba.Lstr(resource='kickVoteText') popup.PopupMenuWindow( position=widget.get_screen_space_center(), scale=2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23, choices=['kick'], choices_display=[kick_str], current_choice='kick', delegate=self) self._popup_type = 'partyMemberPress' self._popup_party_member_client_id = client_id self._popup_party_member_is_host = is_host
def __init__(self, text: Union[str, ba.Lstr] = 'Are you sure?', action: Callable[[], Any] = None, width: float = 360.0, height: float = 100.0, cancel_button: bool = True, cancel_is_selected: bool = False, color: Tuple[float, float, float] = (1, 1, 1), text_scale: float = 1.0, ok_text: Union[str, ba.Lstr] = None, cancel_text: Union[str, ba.Lstr] = None, origin_widget: ba.Widget = None): # pylint: disable=too-many-locals if ok_text is None: ok_text = ba.Lstr(resource='okText') if cancel_text is None: cancel_text = ba.Lstr(resource='cancelText') height += 40 if width < 360: width = 360 self._action = action # if they provided an origin-widget, scale up from that self._transition_out: Optional[str] scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = None scale_origin = None transition = 'in_right' uiscale = ba.app.uiscale self.root_widget = ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal_no_back', parent=_ba.get_special_widget('overlay_stack'), scale=(2.1 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), scale_origin_stack_offset=scale_origin) ba.textwidget(parent=self.root_widget, position=(width * 0.5, height - 5 - (height - 75) * 0.5), size=(0, 0), h_align='center', v_align='center', text=text, scale=text_scale, color=color, maxwidth=width * 0.9, max_height=height - 75) cbtn: Optional[ba.Widget] if cancel_button: cbtn = btn = ba.buttonwidget(parent=self.root_widget, autoselect=True, position=(20, 20), size=(150, 50), label=cancel_text, on_activate_call=self._cancel) ba.containerwidget(edit=self.root_widget, cancel_button=btn) ok_button_h = width - 175 else: # if they don't want a cancel button, we still want back presses to # be able to dismiss the window; just wire it up to do the ok # button ok_button_h = width * 0.5 - 75 cbtn = None btn = ba.buttonwidget(parent=self.root_widget, autoselect=True, position=(ok_button_h, 20), size=(150, 50), label=ok_text, on_activate_call=self._ok) # if they didn't want a cancel button, we still want to be able to hit # cancel/back/etc to dismiss the window if not cancel_button: ba.containerwidget(edit=self.root_widget, on_cancel_call=btn.activate) ba.containerwidget(edit=self.root_widget, selected_child=(cbtn if cbtn is not None and cancel_is_selected else btn), start_button=btn)
def __init__(self, transition: str = 'in_right', modal: bool = False, origin_widget: ba.Widget = None): from ba.internal import get_cached_league_rank_data from ba.deprecated import get_resource ba.set_analytics_screen('League Rank Window') self._league_rank_data: Optional[Dict[str, Any]] = None self._modal = modal # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._width = 1320 if ba.app.small_ui else 1120 x_inset = 100 if ba.app.small_ui else 0 self._height = (657 if ba.app.small_ui else 710 if ba.app.med_ui else 800) self._r = 'coopSelectWindow' self._rdict = get_resource(self._r) top_extra = 20 if ba.app.small_ui else 0 self._league_url_arg = '' self._is_current_season = False self._can_do_more_button = True super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), stack_offset=(0, -15) if ba.app.small_ui else ( 0, 10) if ba.app.med_ui else (0, 0), transition=transition, scale_origin_stack_offset=scale_origin, scale=( 1.2 if ba.app.small_ui else 0.93 if ba.app.med_ui else 0.8))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(75 + x_inset, self._height - 87 - (4 if ba.app.small_ui else 0)), size=(120, 60), scale=1.2, autoselect=True, label=ba.Lstr(resource='doneText' if self._modal else 'backText'), button_type=None if self._modal else 'back', on_activate_call=self._back) self._title_text = ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 56), size=(0, 0), text=ba.Lstr( resource='league.leagueRankText', fallback_resource='coopSelectWindow.powerRankingText'), h_align="center", color=ba.app.title_color, scale=1.4, maxwidth=600, v_align="center") ba.buttonwidget(edit=btn, button_type='backSmall', position=(75 + x_inset, self._height - 87 - (2 if ba.app.small_ui else 0)), size=(60, 55), label=ba.charstr(ba.SpecialChar.BACK)) self._scroll_width = self._width - (130 + 2 * x_inset) self._scroll_height = self._height - 160 self._scrollwidget = ba.scrollwidget(parent=self._root_widget, highlight=False, position=(65 + x_inset, 70), size=(self._scroll_width, self._scroll_height), center_small_content=True) ba.widget(edit=self._scrollwidget, autoselect=True) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) ba.containerwidget(edit=self._root_widget, cancel_button=self._back_button, selected_child=self._back_button) self._last_power_ranking_query_time: Optional[float] = None self._doing_power_ranking_query = False self._subcontainer: Optional[ba.Widget] = None self._subcontainerwidth = 800 self._subcontainerheight = 483 self._power_ranking_score_widgets: List[ba.Widget] = [] self._season_popup_menu: Optional[popup_ui.PopupMenu] = None self._requested_season: Optional[str] = None self._season: Optional[str] = None # take note of our account state; we'll refresh later if this changes self._account_state = _ba.get_account_state() self._refresh() self._restore_state() # if we've got cached power-ranking data already, display it info = get_cached_league_rank_data() if info is not None: self._update_for_league_rank_data(info) self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) self._update(show=(info is None))
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-locals # pylint: disable=too-many-statements # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'editSoundtrackWindow' uiscale = ba.app.uiscale self._width = 800 if uiscale is ba.UIScale.SMALL else 600 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (340 if uiscale is ba.UIScale.SMALL else 370 if uiscale is ba.UIScale.MEDIUM else 440) spacing = 40.0 v = self._height - 40.0 v -= spacing * 1.0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=(2.3 if uiscale is ba.UIScale.SMALL else 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -18) if uiscale is ba.UIScale.SMALL else (0, 0))) if ba.app.toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None else: self._back_button = ba.buttonwidget( parent=self._root_widget, position=(45 + x_inset, self._height - 60), size=(120, 60), scale=0.8, label=ba.Lstr(resource='backText'), button_type='back', autoselect=True) ba.buttonwidget(edit=self._back_button, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 35), size=(0, 0), maxwidth=300, text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.title_color, h_align='center', v_align='center') h = 43 + x_inset v = self._height - 60 b_color = (0.6, 0.53, 0.63) b_textcolor = (0.75, 0.7, 0.8) lock_tex = ba.gettexture('lock') self._lock_images: List[ba.Widget] = [] scl = (1.0 if uiscale is ba.UIScale.SMALL else 1.13 if uiscale is ba.UIScale.MEDIUM else 1.4) v -= 60.0 * scl self._new_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(100, 55.0 * scl), on_activate_call=self._new_soundtrack, color=b_color, button_type='square', autoselect=True, textcolor=b_textcolor, text_scale=0.7, label=ba.Lstr(resource=self._r + '.newText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 55.0 * scl - 28), texture=lock_tex)) if self._back_button is None: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) v -= 60.0 * scl self._edit_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(100, 55.0 * scl), on_activate_call=self._edit_soundtrack, color=b_color, button_type='square', autoselect=True, textcolor=b_textcolor, text_scale=0.7, label=ba.Lstr(resource=self._r + '.editText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 55.0 * scl - 28), texture=lock_tex)) if self._back_button is None: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) v -= 60.0 * scl self._duplicate_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(100, 55.0 * scl), on_activate_call=self._duplicate_soundtrack, button_type='square', autoselect=True, color=b_color, textcolor=b_textcolor, text_scale=0.7, label=ba.Lstr(resource=self._r + '.duplicateText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 55.0 * scl - 28), texture=lock_tex)) if self._back_button is None: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) v -= 60.0 * scl self._delete_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(100, 55.0 * scl), on_activate_call=self._delete_soundtrack, color=b_color, button_type='square', autoselect=True, textcolor=b_textcolor, text_scale=0.7, label=ba.Lstr(resource=self._r + '.deleteText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 55.0 * scl - 28), texture=lock_tex)) if self._back_button is None: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) # Keep our lock images up to date/etc. self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) self._update() v = self._height - 65 scroll_height = self._height - 105 v -= scroll_height self._scrollwidget = scrollwidget = ba.scrollwidget( parent=self._root_widget, position=(152 + x_inset, v), highlight=False, size=(self._width - (205 + 2 * x_inset), scroll_height)) ba.widget(edit=self._scrollwidget, left_widget=self._new_button, right_widget=_ba.get_special_widget('party_button') if ba.app.toolbars else self._scrollwidget) self._col = ba.columnwidget(parent=scrollwidget) self._soundtracks: Optional[Dict[str, Any]] = None self._selected_soundtrack: Optional[str] = None self._selected_soundtrack_index: Optional[int] = None self._soundtrack_widgets: List[ba.Widget] = [] self._allow_changing_soundtracks = False self._refresh() if self._back_button is not None: ba.buttonwidget(edit=self._back_button, on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=self._back_button) else: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back)
def __init__(self, transition: Optional[str] = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-locals # pylint: disable=too-many-statements from bastd.ui.tabs import TabRow ba.set_analytics_screen('Watch Window') scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None ba.app.ui.set_main_menu_location('Watch') self._tab_data: Dict[str, Any] = {} self._my_replays_scroll_width: Optional[float] = None self._my_replays_watch_replay_button: Optional[ba.Widget] = None self._scrollwidget: Optional[ba.Widget] = None self._columnwidget: Optional[ba.Widget] = None self._my_replay_selected: Optional[str] = None self._my_replays_rename_window: Optional[ba.Widget] = None self._my_replay_rename_text: Optional[ba.Widget] = None self._r = 'watchWindow' uiscale = ba.app.ui.uiscale self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (578 if uiscale is ba.UIScale.SMALL else 670 if uiscale is ba.UIScale.MEDIUM else 800) self._current_tab: Optional[WatchWindow.TabID] = None extra_top = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + extra_top), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=(1.3 if uiscale is ba.UIScale.SMALL else 0.97 if uiscale is ba.UIScale.MEDIUM else 0.8), stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( 0, 15) if uiscale is ba.UIScale.MEDIUM else (0, 0))) if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) self._back_button = None else: self._back_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(70 + x_inset, self._height - 74), size=(140, 60), scale=1.1, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 38), size=(0, 0), color=ba.app.ui.title_color, scale=1.5, h_align='center', v_align='center', text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=400) tabdefs = [ (self.TabID.MY_REPLAYS, ba.Lstr(resource=self._r + '.myReplaysText')), # (self.TabID.TEST_TAB, ba.Lstr(value='Testing')), ] scroll_buffer_h = 130 + 2 * x_inset tab_buffer_h = 750 + 2 * x_inset self._tab_row = TabRow(self._root_widget, tabdefs, pos=(tab_buffer_h * 0.5, self._height - 130), size=(self._width - tab_buffer_h, 50), on_select_call=self._set_tab) if ba.app.ui.use_toolbars: first_tab = self._tab_row.tabs[tabdefs[0][0]] last_tab = self._tab_row.tabs[tabdefs[-1][0]] ba.widget(edit=last_tab.button, right_widget=_ba.get_special_widget('party_button')) if uiscale is ba.UIScale.SMALL: bbtn = _ba.get_special_widget('back_button') ba.widget(edit=first_tab.button, up_widget=bbtn, left_widget=bbtn) self._scroll_width = self._width - scroll_buffer_h self._scroll_height = self._height - 180 # Not actually using a scroll widget anymore; just an image. scroll_left = (self._width - self._scroll_width) * 0.5 scroll_bottom = self._height - self._scroll_height - 79 - 48 buffer_h = 10 buffer_v = 4 ba.imagewidget(parent=self._root_widget, position=(scroll_left - buffer_h, scroll_bottom - buffer_v), size=(self._scroll_width + 2 * buffer_h, self._scroll_height + 2 * buffer_v), texture=ba.gettexture('scrollWidget'), model_transparent=ba.getmodel('softEdgeOutside')) self._tab_container: Optional[ba.Widget] = None self._restore_state()
def __init__(self, origin_widget: ba.Widget = None): scale_origin: Optional[tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None transition = 'in_right' bg_color = (0.4, 0.4, 0.5) self._width = 540 self._height = 350 self._scroll_width = 400 self._scroll_height = 200 uiscale = ba.app.ui.uiscale base_scale = (2.0 if uiscale is ba.UIScale.SMALL else 1.6 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, position=(30, self._height - 50), size=(50, 50), scale=0.7, label='', color=bg_color, on_activate_call=self._cancel, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.88), size=(0, 0), text=ba.Lstr( resource='accountSettingsWindow.unlinkAccountsInstructionsText' ), maxwidth=self._width * 0.7, color=ba.app.ui.infotextcolor, h_align='center', v_align='center') ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, position=((self._width - self._scroll_width) * 0.5, self._height - 85 - self._scroll_height), size=(self._scroll_width, self._scroll_height)) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._columnwidget = ba.columnwidget(parent=self._scrollwidget, border=2, margin=0, left_border=10) our_login_id = _ba.get_public_login_id() if our_login_id is None: entries = [] else: account_infos = _ba.get_account_misc_read_val_2( 'linkedAccounts2', []) entries = [{ 'name': ai['d'], 'id': ai['id'] } for ai in account_infos if ai['id'] != our_login_id] # (avoid getting our selection stuck on an empty column widget) if not entries: ba.containerwidget(edit=self._scrollwidget, selectable=False) for i, entry in enumerate(entries): txt = ba.textwidget(parent=self._columnwidget, selectable=True, text=entry['name'], size=(self._scroll_width - 30, 30), autoselect=True, click_activate=True, on_activate_call=ba.Call( self._on_entry_selected, entry)) ba.widget(edit=txt, left_widget=self._cancel_button) if i == 0: ba.widget(edit=txt, up_widget=self._cancel_button)
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals # pylint: disable=cyclic-import from bastd.ui.popup import PopupMenu from bastd.ui.config import ConfigNumberEdit music = ba.app.music # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'audioSettingsWindow' spacing = 50.0 width = 460.0 height = 210.0 # Update: hard-coding head-relative audio to true now, # so not showing options. # show_vr_head_relative_audio = True if ba.app.vr_mode else False show_vr_head_relative_audio = False if show_vr_head_relative_audio: height += 70 show_soundtracks = False if music.have_music_player(): show_soundtracks = True height += spacing * 2.0 uiscale = ba.app.ui.uiscale base_scale = (2.05 if uiscale is ba.UIScale.SMALL else 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0) popup_menu_scale = base_scale * 1.2 super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, stack_offset=(0, -20) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(35, height - 55), size=(120, 60), scale=0.8, text_scale=1.2, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._back, autoselect=True) ba.containerwidget(edit=self._root_widget, cancel_button=btn) v = height - 60 v -= spacing * 1.0 ba.textwidget(parent=self._root_widget, position=(width * 0.5, height - 32), size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.ui.title_color, maxwidth=180, h_align='center', v_align='center') ba.buttonwidget(edit=self._back_button, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) self._sound_volume_numedit = svne = ConfigNumberEdit( parent=self._root_widget, position=(40, v), xoffset=10, configkey='Sound Volume', displayname=ba.Lstr(resource=self._r + '.soundVolumeText'), minval=0.0, maxval=1.0, increment=0.1) if ba.app.ui.use_toolbars: ba.widget(edit=svne.plusbutton, right_widget=_ba.get_special_widget('party_button')) v -= spacing self._music_volume_numedit = ConfigNumberEdit( parent=self._root_widget, position=(40, v), xoffset=10, configkey='Music Volume', displayname=ba.Lstr(resource=self._r + '.musicVolumeText'), minval=0.0, maxval=1.0, increment=0.1, callback=music.music_volume_changed, changesound=False) v -= 0.5 * spacing self._vr_head_relative_audio_button: Optional[ba.Widget] if show_vr_head_relative_audio: v -= 40 ba.textwidget(parent=self._root_widget, position=(40, v + 24), size=(0, 0), text=ba.Lstr(resource=self._r + '.headRelativeVRAudioText'), color=(0.8, 0.8, 0.8), maxwidth=230, h_align='left', v_align='center') popup = PopupMenu( parent=self._root_widget, position=(290, v), width=120, button_size=(135, 50), scale=popup_menu_scale, choices=['Auto', 'On', 'Off'], choices_display=[ ba.Lstr(resource='autoText'), ba.Lstr(resource='onText'), ba.Lstr(resource='offText') ], current_choice=ba.app.config.resolve('VR Head Relative Audio'), on_value_change_call=self._set_vr_head_relative_audio) self._vr_head_relative_audio_button = popup.get_button() ba.textwidget(parent=self._root_widget, position=(width * 0.5, v - 11), size=(0, 0), text=ba.Lstr(resource=self._r + '.headRelativeVRAudioInfoText'), scale=0.5, color=(0.7, 0.8, 0.7), maxwidth=400, flatness=1.0, h_align='center', v_align='center') v -= 30 else: self._vr_head_relative_audio_button = None self._soundtrack_button: Optional[ba.Widget] if show_soundtracks: v -= 1.2 * spacing self._soundtrack_button = ba.buttonwidget( parent=self._root_widget, position=((width - 310) / 2, v), size=(310, 50), autoselect=True, label=ba.Lstr(resource=self._r + '.soundtrackButtonText'), on_activate_call=self._do_soundtracks) v -= spacing * 0.5 ba.textwidget(parent=self._root_widget, position=(0, v), size=(width, 20), text=ba.Lstr(resource=self._r + '.soundtrackDescriptionText'), flatness=1.0, h_align='center', scale=0.5, color=(0.7, 0.8, 0.7, 1.0), maxwidth=400) else: self._soundtrack_button = None # Tweak a few navigation bits. try: ba.widget(edit=back_button, down_widget=svne.minusbutton) except Exception: ba.print_exception('Error wiring AudioSettingsWindow.') self._restore_state()
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # FIXME: should tidy up here. # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=cyclic-import from bastd.ui import popup as popup_ui self._have_selected_child = False scale_origin: Optional[Tuple[float, float]] # If they provided an origin-widget, scale up from that. if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'configControllersWindow' app = ba.app is_fire_tv = _ba.is_running_on_fire_tv() spacing = 50.0 button_width = 350.0 width = 460.0 height = 135.0 space_height = spacing * 0.3 # FIXME: should create vis settings in platform for these, # not hard code them here.. show_gamepads = False platform = app.platform subplatform = app.subplatform non_vr_windows = (platform == 'windows' and (subplatform != 'oculus' or not app.vr_mode)) if platform in ('linux', 'android', 'mac') or non_vr_windows: show_gamepads = True height += spacing show_touch = False if _ba.have_touchscreen_input(): show_touch = True height += spacing show_space_1 = False if show_gamepads or show_touch: show_space_1 = True height += space_height show_keyboard = False if _ba.getinputdevice('Keyboard', '#1', doraise=False) is not None: show_keyboard = True height += spacing * 2 show_keyboard_p2 = False if app.vr_mode else show_keyboard if show_keyboard_p2: height += spacing show_space_2 = False if show_keyboard: show_space_2 = True height += space_height if bool(True): show_remote = True height += spacing else: show_remote = False show_ps3 = False if platform == 'mac': show_ps3 = True height += spacing show360 = False if platform == 'mac' or is_fire_tv: show360 = True height += spacing show_mac_wiimote = False if platform == 'mac': show_mac_wiimote = True height += spacing # on non-oculus-vr windows, show an option to disable xinput show_xinput_toggle = False if platform == 'windows' and (subplatform != 'oculus' or not app.vr_mode): show_xinput_toggle = True # on mac builds, show an option to switch between generic and # made-for-iOS/Mac systems # (we can run into problems where devices register as one of each # type otherwise).. show_mac_controller_subsystem = False if platform == 'mac': show_mac_controller_subsystem = True if show_mac_controller_subsystem: height += spacing if show_xinput_toggle: height += spacing super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, scale_origin_stack_offset=scale_origin, scale=(1.7 if show_keyboard else 2.2 ) if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0)) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(35, height - 60), size=(140, 65), scale=0.8, text_scale=1.2, autoselect=True, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) # need these vars to exist even if the buttons don't self._gamepads_button: Optional[ba.Widget] = None self._touch_button: Optional[ba.Widget] = None self._keyboard_button: Optional[ba.Widget] = None self._keyboard_2_button: Optional[ba.Widget] = None self._idevices_button: Optional[ba.Widget] = None self._ps3_button: Optional[ba.Widget] = None self._xbox_360_button: Optional[ba.Widget] = None self._wiimotes_button: Optional[ba.Widget] = None ba.textwidget(parent=self._root_widget, position=(0, height - 49), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.title_color, h_align='center', v_align='top') ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) v = height - 75 v -= spacing if show_touch: self._touch_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.configureTouchText'), on_activate_call=self._do_touchscreen) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: ba.containerwidget(edit=self._root_widget, selected_child=self._touch_button) ba.widget(edit=self._back_button, down_widget=self._touch_button) self._have_selected_child = True v -= spacing if show_gamepads: self._gamepads_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 - 7, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.configureControllersText'), on_activate_call=self._do_gamepads) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: ba.containerwidget(edit=self._root_widget, selected_child=self._gamepads_button) ba.widget(edit=self._back_button, down_widget=self._gamepads_button) self._have_selected_child = True v -= spacing else: self._gamepads_button = None if show_space_1: v -= space_height if show_keyboard: self._keyboard_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 + 5, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.configureKeyboardText'), on_activate_call=self._config_keyboard) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: ba.containerwidget(edit=self._root_widget, selected_child=self._keyboard_button) ba.widget(edit=self._back_button, down_widget=self._keyboard_button) self._have_selected_child = True v -= spacing if show_keyboard_p2: self._keyboard_2_button = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 - 3, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.configureKeyboard2Text'), on_activate_call=self._config_keyboard2) v -= spacing if show_space_2: v -= space_height if show_remote: self._idevices_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 - 5, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.configureMobileText'), on_activate_call=self._do_mobile_devices) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: ba.containerwidget(edit=self._root_widget, selected_child=self._idevices_button) ba.widget(edit=self._back_button, down_widget=self._idevices_button) self._have_selected_child = True v -= spacing if show_ps3: self._ps3_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 + 5, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.ps3Text'), on_activate_call=self._do_ps3_controllers) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) v -= spacing if show360: self._xbox_360_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 - 1, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.xbox360Text'), on_activate_call=self._do_360_controllers) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) v -= spacing if show_mac_wiimote: self._wiimotes_button = btn = ba.buttonwidget( parent=self._root_widget, position=((width - button_width) / 2 + 5, v), size=(button_width, 43), autoselect=True, label=ba.Lstr(resource=self._r + '.wiimotesText'), on_activate_call=self._do_wiimotes) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) v -= spacing if show_xinput_toggle: def do_toggle(value: bool) -> None: ba.screenmessage( ba.Lstr(resource='settingsWindowAdvanced.mustRestartText'), color=(1, 1, 0)) ba.playsound(ba.getsound('gunCocking')) _ba.set_low_level_config_value('enablexinput', not value) ba.checkboxwidget( parent=self._root_widget, position=(100, v + 3), size=(120, 30), value=(not _ba.get_low_level_config_value('enablexinput', 1)), maxwidth=200, on_value_change_call=do_toggle, text=ba.Lstr(resource='disableXInputText'), autoselect=True) ba.textwidget( parent=self._root_widget, position=(width * 0.5, v - 5), size=(0, 0), text=ba.Lstr(resource='disableXInputDescriptionText'), scale=0.5, h_align='center', v_align='center', color=ba.app.infotextcolor, maxwidth=width * 0.8) v -= spacing if show_mac_controller_subsystem: popup_ui.PopupMenu( parent=self._root_widget, position=(260, v - 10), width=160, button_size=(150, 50), scale=1.5, choices=['Classic', 'MFi', 'Both'], choices_display=[ ba.Lstr(resource='macControllerSubsystemClassicText'), ba.Lstr(resource='macControllerSubsystemMFiText'), ba.Lstr(resource='macControllerSubsystemBothText') ], current_choice=ba.app.config.resolve( 'Mac Controller Subsystem'), on_value_change_call=self._set_mac_controller_subsystem) ba.textwidget( parent=self._root_widget, position=(245, v + 13), size=(0, 0), text=ba.Lstr(resource='macControllerSubsystemTitleText'), scale=1.0, h_align='right', v_align='center', color=ba.app.infotextcolor, maxwidth=180) ba.textwidget( parent=self._root_widget, position=(width * 0.5, v - 20), size=(0, 0), text=ba.Lstr(resource='macControllerSubsystemDescriptionText'), scale=0.5, h_align='center', v_align='center', color=ba.app.infotextcolor, maxwidth=width * 0.8) v -= spacing self._restore_state()
def __init__(self, origin_widget: ba.Widget = None): # pylint: disable=too-many-locals # pylint: disable=too-many-statements import json ba.set_analytics_screen('Credits Window') # if they provided an origin-widget, scale up from that scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None transition = 'in_right' uiscale = ba.app.uiscale width = 870 if uiscale is ba.UIScale.SMALL else 670 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 height = 398 if uiscale is ba.UIScale.SMALL else 500 self._r = 'creditsWindow' super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=(2.0 if uiscale is ba.UIScale.SMALL else 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -8) if uiscale is ba.UIScale.SMALL else (0, 0))) if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) else: btn = ba.buttonwidget( parent=self._root_widget, position=(40 + x_inset, height - (68 if uiscale is ba.UIScale.SMALL else 62)), size=(140, 60), scale=0.8, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._back, autoselect=True) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.buttonwidget( edit=btn, button_type='backSmall', position=(40 + x_inset, height - (68 if uiscale is ba.UIScale.SMALL else 62) + 5), size=(60, 48), label=ba.charstr(ba.SpecialChar.BACK)) ba.textwidget(parent=self._root_widget, position=(0, height - (59 if uiscale is ba.UIScale.SMALL else 54)), size=(width, 30), text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), h_align='center', color=ba.app.ui.title_color, maxwidth=330, v_align='center') scroll = ba.scrollwidget(parent=self._root_widget, position=(40 + x_inset, 35), size=(width - (80 + 2 * x_inset), height - 100), capture_arrows=True) if ba.app.ui.use_toolbars: ba.widget(edit=scroll, right_widget=_ba.get_special_widget('party_button')) if uiscale is ba.UIScale.SMALL: ba.widget(edit=scroll, left_widget=_ba.get_special_widget('back_button')) def _format_names(names2: Sequence[str], inset: float) -> str: sval = '' # measure a series since there's overlaps and stuff.. space_width = _ba.get_string_width(' ' * 10, suppress_warning=True) / 10.0 spacing = 330.0 col1 = inset col2 = col1 + spacing col3 = col2 + spacing line_width = 0.0 nline = '' for name in names2: # move to the next column (or row) and print if line_width > col3: sval += nline + '\n' nline = '' line_width = 0 if line_width > col2: target = col3 elif line_width > col1: target = col2 else: target = col1 spacingstr = ' ' * int((target - line_width) / space_width) nline += spacingstr nline += name line_width = _ba.get_string_width(nline, suppress_warning=True) if nline != '': sval += nline + '\n' return sval sound_and_music = ba.Lstr(resource=self._r + '.songCreditText').evaluate() sound_and_music = sound_and_music.replace( '${TITLE}', "'William Tell (Trumpet Entry)'") sound_and_music = sound_and_music.replace( '${PERFORMER}', 'The Apollo Symphony Orchestra') sound_and_music = sound_and_music.replace( '${PERFORMER}', 'The Apollo Symphony Orchestra') sound_and_music = sound_and_music.replace('${COMPOSER}', 'Gioacchino Rossini') sound_and_music = sound_and_music.replace('${ARRANGER}', 'Chris Worth') sound_and_music = sound_and_music.replace('${PUBLISHER}', 'BMI') sound_and_music = sound_and_music.replace('${SOURCE}', 'www.AudioSparx.com') spc = ' ' sound_and_music = spc + sound_and_music.replace('\n', '\n' + spc) names = [ 'HubOfTheUniverseProd', 'Jovica', 'LG', 'Leady', 'Percy Duke', 'PhreaKsAccount', 'Pogotron', 'Rock Savage', 'anamorphosis', 'benboncan', 'cdrk', 'chipfork', 'guitarguy1985', 'jascha', 'joedeshon', 'loofa', 'm_O_m', 'mich3d', 'sandyrb', 'shakaharu', 'sirplus', 'stickman', 'thanvannispen', 'virotic', 'zimbot' ] names.sort(key=lambda x: x.lower()) freesound_names = _format_names(names, 90) try: with open('ba_data/data/langdata.json') as infile: translation_contributors = (json.loads( infile.read())['translation_contributors']) except Exception: ba.print_exception('Error reading translation contributors.') translation_contributors = [] translation_names = _format_names(translation_contributors, 60) # Need to bake this out and chop it up since we're passing our # 65535 vertex limit for meshes.. # We can remove that limit once we drop support for GL ES2.. :-/ # (or add mesh splitting under the hood) credits_text = ( ' ' + ba.Lstr(resource=self._r + '.codingGraphicsAudioText').evaluate().replace( '${NAME}', 'Eric Froemling') + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.additionalAudioArtIdeasText').evaluate().replace( '${NAME}', 'Raphael Suter') + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.soundAndMusicText').evaluate() + '\n' '\n' + sound_and_music + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.publicDomainMusicViaText').evaluate().replace( '${NAME}', 'Musopen.com') + '\n' ' ' + ba.Lstr(resource=self._r + '.thanksEspeciallyToText').evaluate().replace( '${NAME}', 'the US Army, Navy, and Marine Bands') + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.additionalMusicFromText').evaluate().replace( '${NAME}', 'The YouTube Audio Library') + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.soundsText').evaluate().replace( '${SOURCE}', 'Freesound.org') + '\n' '\n' + freesound_names + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.languageTranslationsText').evaluate() + '\n' '\n' + '\n'.join(translation_names.splitlines()[:146]) + '\n'.join(translation_names.splitlines()[146:]) + '\n' '\n' ' Shout Out to Awesome Mods / Modders:\n\n' ' BombDash ModPack\n' ' TheMikirog & SoK - BombSquad Joyride Modpack\n' ' Mrmaxmeier - BombSquad-Community-Mod-Manager\n' '\n' ' Holiday theme vector art designed by Freepik\n' '\n' ' ' + ba.Lstr(resource=self._r + '.specialThanksText').evaluate() + '\n' '\n' ' Todd, Laura, and Robert Froemling\n' ' ' + ba.Lstr(resource=self._r + '.allMyFamilyText').evaluate().replace( '\n', '\n ') + '\n' ' ' + ba.Lstr(resource=self._r + '.whoeverInventedCoffeeText').evaluate() + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.legalText').evaluate() + '\n' '\n' ' ' + ba.Lstr(resource=self._r + '.softwareBasedOnText').evaluate().replace( '${NAME}', 'the Khronos Group') + '\n' '\n' ' ' ' www.froemling.net\n') txt = credits_text lines = txt.splitlines() line_height = 20 scale = 0.55 self._sub_width = width - 80 self._sub_height = line_height * len(lines) + 40 container = self._subcontainer = ba.containerwidget( parent=scroll, size=(self._sub_width, self._sub_height), background=False, claims_left_right=False, claims_tab=False) voffs = 0 for line in lines: ba.textwidget(parent=container, padding=4, color=(0.7, 0.9, 0.7, 1.0), scale=scale, flatness=1.0, size=(0, 0), position=(0, self._sub_height - 20 + voffs), h_align='left', v_align='top', text=ba.Lstr(value=line)) voffs -= line_height
def __init__(self, main_menu: bool = False, origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals from ba.internal import get_remote_app_name from ba.deprecated import get_resource ba.set_analytics_screen('Help Window') # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None transition = 'in_right' self._r = 'helpWindow' self._main_menu = main_menu width = 950 if ba.app.small_ui else 750 x_offs = 100 if ba.app.small_ui else 0 height = 460 if ba.app.small_ui else 530 if ba.app.med_ui else 600 super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=( 1.77 if ba.app.small_ui else 1.25 if ba.app.med_ui else 1.0), stack_offset=(0, -30) if ba.app.small_ui else ( 0, 15) if ba.app.med_ui else (0, 0))) ba.textwidget(parent=self._root_widget, position=(0, height - (50 if ba.app.small_ui else 45)), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), color=ba.app.title_color, h_align='center', v_align='top') self._scrollwidget = ba.scrollwidget( parent=self._root_widget, position=(44 + x_offs, 55 if ba.app.small_ui else 55), simple_culling_v=100.0, size=(width - (88 + 2 * x_offs), height - 120 + (5 if ba.app.small_ui else 0)), capture_arrows=True) if ba.app.toolbars: ba.widget(edit=self._scrollwidget, right_widget=_ba.get_special_widget('party_button')) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) # ugly: create this last so it gets first dibs at touch events (since # we have it close to the scroll widget) if ba.app.small_ui and ba.app.toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._close) ba.widget(edit=self._scrollwidget, left_widget=_ba.get_special_widget('back_button')) else: btn = ba.buttonwidget( parent=self._root_widget, position=(x_offs + (40 + 0 if ba.app.small_ui else 70), height - (59 if ba.app.small_ui else 50)), size=(140, 60), scale=0.7 if ba.app.small_ui else 0.8, label=ba.Lstr( resource='backText') if self._main_menu else 'Close', button_type='back' if self._main_menu else None, extra_touch_border_scale=2.0, autoselect=True, on_activate_call=self._close) ba.containerwidget(edit=self._root_widget, cancel_button=btn) if self._main_menu: ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 55), label=ba.charstr(ba.SpecialChar.BACK)) # interface_type = ba.app.interface_type self._sub_width = 660 self._sub_height = 1590 + get_resource( self._r + '.someDaysExtraSpace') + get_resource( self._r + '.orPunchingSomethingExtraSpace') self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), background=False, claims_left_right=False, claims_tab=False) spacing = 1.0 h = self._sub_width * 0.5 v = self._sub_height - 55 logo_tex = ba.gettexture('logo') icon_buffer = 1.1 header = (0.7, 1.0, 0.7, 1.0) header2 = (0.8, 0.8, 1.0, 1.0) paragraph = (0.8, 0.8, 1.0, 1.0) txt = ba.Lstr(resource=self._r + '.welcomeText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate() txt_scale = 1.4 txt_maxwidth = 480 ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, flatness=0.5, res_scale=1.5, text=txt, h_align='center', color=header, v_align='center', maxwidth=txt_maxwidth) txt_width = min( txt_maxwidth, _ba.get_string_width(txt, suppress_warning=True) * txt_scale) icon_size = 70 hval2 = h - (txt_width * 0.5 + icon_size * 0.5 * icon_buffer) ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, v - 0.45 * icon_size), texture=logo_tex) force_test = False app = ba.app if (app.platform == 'android' and app.subplatform == 'alibaba') or force_test: v -= 120.0 txtv = ( '\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe4\xb8\xaa\xe5\x8f\xaf' '\xe4\xbb\xa5\xe5\x92\x8c\xe5\xae\xb6\xe4\xba\xba\xe6\x9c\x8b' '\xe5\x8f\x8b\xe4\xb8\x80\xe8\xb5\xb7\xe7\x8e\xa9\xe7\x9a\x84' '\xe6\xb8\xb8\xe6\x88\x8f,\xe5\x90\x8c\xe6\x97\xb6\xe6\x94\xaf' '\xe6\x8c\x81\xe8\x81\x94 \xe2\x80\xa8\xe7\xbd\x91\xe5\xaf\xb9' '\xe6\x88\x98\xe3\x80\x82\n' '\xe5\xa6\x82\xe6\xb2\xa1\xe6\x9c\x89\xe6\xb8\xb8\xe6\x88\x8f' '\xe6\x89\x8b\xe6\x9f\x84,\xe5\x8f\xaf\xe4\xbb\xa5\xe4\xbd\xbf' '\xe7\x94\xa8\xe7\xa7\xbb\xe5\x8a\xa8\xe8\xae\xbe\xe5\xa4\x87' '\xe6\x89\xab\xe7\xa0\x81\xe4\xb8\x8b\xe8\xbd\xbd\xe2\x80\x9c' '\xe9\x98\xbf\xe9\x87\x8c\xc2' '\xa0TV\xc2\xa0\xe5\x8a\xa9\xe6\x89' '\x8b\xe2\x80\x9d\xe7\x94\xa8 \xe6\x9d\xa5\xe4\xbb\xa3\xe6\x9b' '\xbf\xe5\xa4\x96\xe8\xae\xbe\xe3\x80\x82\n' '\xe6\x9c\x80\xe5\xa4\x9a\xe6\x94\xaf\xe6\x8c\x81\xe6\x8e\xa5' '\xe5\x85\xa5\xc2\xa08\xc2\xa0\xe4\xb8\xaa\xe5\xa4\x96\xe8' '\xae\xbe') ba.textwidget(parent=self._subcontainer, size=(0, 0), h_align='center', v_align='center', maxwidth=self._sub_width * 0.9, position=(self._sub_width * 0.5, v - 180), text=txtv) ba.imagewidget(parent=self._subcontainer, position=(self._sub_width - 320, v - 120), size=(200, 200), texture=ba.gettexture('aliControllerQR')) ba.imagewidget(parent=self._subcontainer, position=(90, v - 130), size=(210, 210), texture=ba.gettexture('multiplayerExamples')) v -= 120.0 else: v -= spacing * 50.0 txt = ba.Lstr(resource=self._r + '.someDaysText').evaluate() ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=1.2, maxwidth=self._sub_width * 0.9, text=txt, h_align='center', color=paragraph, v_align='center', flatness=1.0) v -= (spacing * 25.0 + get_resource(self._r + '.someDaysExtraSpace')) txt_scale = 0.66 txt = ba.Lstr(resource=self._r + '.orPunchingSomethingText').evaluate() ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, maxwidth=self._sub_width * 0.9, text=txt, h_align='center', color=paragraph, v_align='center', flatness=1.0) v -= (spacing * 27.0 + get_resource(self._r + '.orPunchingSomethingExtraSpace')) txt_scale = 1.0 txt = ba.Lstr(resource=self._r + '.canHelpText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate() ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, flatness=1.0, text=txt, h_align='center', color=paragraph, v_align='center') v -= spacing * 70.0 txt_scale = 1.0 txt = ba.Lstr(resource=self._r + '.toGetTheMostText').evaluate() ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, maxwidth=self._sub_width * 0.9, text=txt, h_align='center', color=header, v_align='center', flatness=1.0) v -= spacing * 40.0 txt_scale = 0.74 txt = ba.Lstr(resource=self._r + '.friendsText').evaluate() hval2 = h - 220 ba.textwidget(parent=self._subcontainer, position=(hval2, v), size=(0, 0), scale=txt_scale, maxwidth=100, text=txt, h_align='right', color=header, v_align='center', flatness=1.0) txt = ba.Lstr(resource=self._r + '.friendsGoodText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate() txt_scale = 0.7 ba.textwidget(parent=self._subcontainer, position=(hval2 + 10, v + 8), size=(0, 0), scale=txt_scale, maxwidth=500, text=txt, h_align='left', color=paragraph, flatness=1.0) app = ba.app v -= spacing * 45.0 txt = (ba.Lstr(resource=self._r + '.devicesText').evaluate() if app.vr_mode else ba.Lstr(resource=self._r + '.controllersText').evaluate()) txt_scale = 0.74 hval2 = h - 220 ba.textwidget(parent=self._subcontainer, position=(hval2, v), size=(0, 0), scale=txt_scale, maxwidth=100, text=txt, h_align='right', color=header, v_align='center', flatness=1.0) txt_scale = 0.7 if not app.vr_mode: txt = ba.Lstr(resource=self._r + '.controllersInfoText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')), ('${REMOTE_APP_NAME}', get_remote_app_name())]).evaluate() else: txt = ba.Lstr(resource=self._r + '.devicesInfoText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate() ba.textwidget(parent=self._subcontainer, position=(hval2 + 10, v + 8), size=(0, 0), scale=txt_scale, maxwidth=500, max_height=105, text=txt, h_align='left', color=paragraph, flatness=1.0) v -= spacing * 150.0 txt = ba.Lstr(resource=self._r + '.controlsText').evaluate() txt_scale = 1.4 txt_maxwidth = 480 ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, flatness=0.5, text=txt, h_align='center', color=header, v_align='center', res_scale=1.5, maxwidth=txt_maxwidth) txt_width = min( txt_maxwidth, _ba.get_string_width(txt, suppress_warning=True) * txt_scale) icon_size = 70 hval2 = h - (txt_width * 0.5 + icon_size * 0.5 * icon_buffer) ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, v - 0.45 * icon_size), texture=logo_tex) v -= spacing * 45.0 txt_scale = 0.7 txt = ba.Lstr(resource=self._r + '.controlsSubtitleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate() ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, maxwidth=self._sub_width * 0.9, flatness=1.0, text=txt, h_align='center', color=paragraph, v_align='center') v -= spacing * 160.0 sep = 70 icon_size = 100 # icon_size_2 = 30 hval2 = h - sep vval2 = v ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, vval2 - 0.5 * icon_size), texture=ba.gettexture('buttonPunch'), color=(1, 0.7, 0.3)) txt_scale = get_resource(self._r + '.punchInfoTextScale') txt = ba.Lstr(resource=self._r + '.punchInfoText').evaluate() ba.textwidget(parent=self._subcontainer, position=(h - sep - 185 + 70, v + 120), size=(0, 0), scale=txt_scale, flatness=1.0, text=txt, h_align='center', color=(1, 0.7, 0.3, 1.0), v_align='top') hval2 = h + sep vval2 = v ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, vval2 - 0.5 * icon_size), texture=ba.gettexture('buttonBomb'), color=(1, 0.3, 0.3)) txt = ba.Lstr(resource=self._r + '.bombInfoText').evaluate() txt_scale = get_resource(self._r + '.bombInfoTextScale') ba.textwidget(parent=self._subcontainer, position=(h + sep + 50 + 60, v - 35), size=(0, 0), scale=txt_scale, flatness=1.0, maxwidth=270, text=txt, h_align='center', color=(1, 0.3, 0.3, 1.0), v_align='top') hval2 = h vval2 = v + sep ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, vval2 - 0.5 * icon_size), texture=ba.gettexture('buttonPickUp'), color=(0.5, 0.5, 1)) txtl = ba.Lstr(resource=self._r + '.pickUpInfoText') txt_scale = get_resource(self._r + '.pickUpInfoTextScale') ba.textwidget(parent=self._subcontainer, position=(h + 60 + 120, v + sep + 50), size=(0, 0), scale=txt_scale, flatness=1.0, text=txtl, h_align='center', color=(0.5, 0.5, 1, 1.0), v_align='top') hval2 = h vval2 = v - sep ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, vval2 - 0.5 * icon_size), texture=ba.gettexture('buttonJump'), color=(0.4, 1, 0.4)) txt = ba.Lstr(resource=self._r + '.jumpInfoText').evaluate() txt_scale = get_resource(self._r + '.jumpInfoTextScale') ba.textwidget(parent=self._subcontainer, position=(h - 250 + 75, v - sep - 15 + 30), size=(0, 0), scale=txt_scale, flatness=1.0, text=txt, h_align='center', color=(0.4, 1, 0.4, 1.0), v_align='top') txt = ba.Lstr(resource=self._r + '.runInfoText').evaluate() txt_scale = get_resource(self._r + '.runInfoTextScale') ba.textwidget(parent=self._subcontainer, position=(h, v - sep - 100), size=(0, 0), scale=txt_scale, maxwidth=self._sub_width * 0.93, flatness=1.0, text=txt, h_align='center', color=(0.7, 0.7, 1.0, 1.0), v_align='center') v -= spacing * 280.0 txt = ba.Lstr(resource=self._r + '.powerupsText').evaluate() txt_scale = 1.4 txt_maxwidth = 480 ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, flatness=0.5, text=txt, h_align='center', color=header, v_align='center', maxwidth=txt_maxwidth) txt_width = min( txt_maxwidth, _ba.get_string_width(txt, suppress_warning=True) * txt_scale) icon_size = 70 hval2 = h - (txt_width * 0.5 + icon_size * 0.5 * icon_buffer) ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(hval2 - 0.5 * icon_size, v - 0.45 * icon_size), texture=logo_tex) v -= spacing * 50.0 txt_scale = get_resource(self._r + '.powerupsSubtitleTextScale') txt = ba.Lstr(resource=self._r + '.powerupsSubtitleText').evaluate() ba.textwidget(parent=self._subcontainer, position=(h, v), size=(0, 0), scale=txt_scale, maxwidth=self._sub_width * 0.9, text=txt, h_align='center', color=paragraph, v_align='center', flatness=1.0) v -= spacing * 1.0 mm1 = -270 mm2 = -215 mm3 = 0 icon_size = 50 shadow_size = 80 shadow_offs_x = 3 shadow_offs_y = -4 t_big = 1.1 t_small = 0.65 shadow_tex = ba.gettexture('shadowSharp') for tex in [ 'powerupPunch', 'powerupShield', 'powerupBomb', 'powerupHealth', 'powerupIceBombs', 'powerupImpactBombs', 'powerupStickyBombs', 'powerupLandMines', 'powerupCurse' ]: name = ba.Lstr(resource=self._r + '.' + tex + 'NameText') desc = ba.Lstr(resource=self._r + '.' + tex + 'DescriptionText') v -= spacing * 60.0 ba.imagewidget( parent=self._subcontainer, size=(shadow_size, shadow_size), position=(h + mm1 + shadow_offs_x - 0.5 * shadow_size, v + shadow_offs_y - 0.5 * shadow_size), texture=shadow_tex, color=(0, 0, 0), opacity=0.5) ba.imagewidget(parent=self._subcontainer, size=(icon_size, icon_size), position=(h + mm1 - 0.5 * icon_size, v - 0.5 * icon_size), texture=ba.gettexture(tex)) txt_scale = t_big txtl = name ba.textwidget(parent=self._subcontainer, position=(h + mm2, v + 3), size=(0, 0), scale=txt_scale, maxwidth=200, flatness=1.0, text=txtl, h_align='left', color=header2, v_align='center') txt_scale = t_small txtl = desc ba.textwidget(parent=self._subcontainer, position=(h + mm3, v), size=(0, 0), scale=txt_scale, maxwidth=300, flatness=1.0, text=txtl, h_align='left', color=paragraph, v_align='center', res_scale=0.5)
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-locals app = ba.app # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None uiscale = ba.app.ui.uiscale self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (390.0 if uiscale is ba.UIScale.SMALL else 450.0 if uiscale is ba.UIScale.MEDIUM else 520.0) top_extra = 10 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=(2.06 if uiscale is ba.UIScale.SMALL else 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -25) if uiscale is ba.UIScale.SMALL else (0, 0))) self._scroll_width = self._width - (100 + 2 * x_inset) self._scroll_height = self._height - 115.0 self._sub_width = self._scroll_width * 0.95 self._sub_height = 724.0 if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._do_back) self._back_button = None else: self._back_button = ba.buttonwidget( parent=self._root_widget, position=(53 + x_inset, self._height - 60), size=(140, 60), scale=0.8, autoselect=True, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._do_back) ba.containerwidget(edit=self._root_widget, cancel_button=self._back_button) self._title_text = ba.textwidget(parent=self._root_widget, position=(0, self._height - 52), size=(self._width, 25), text=ba.Lstr(resource='pluginsText'), color=app.ui.title_color, h_align='center', v_align='top') if self._back_button is not None: ba.buttonwidget(edit=self._back_button, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) self._scrollwidget = ba.scrollwidget(parent=self._root_widget, position=(50 + x_inset, 50), simple_culling_v=20.0, highlight=False, size=(self._scroll_width, self._scroll_height), selection_loops_to_parent=True) ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) self._subcontainer = ba.columnwidget(parent=self._scrollwidget, selection_loops_to_parent=True) if ba.app.metascan is None: ba.screenmessage('Still scanning plugins; please try again.', color=(1, 0, 0)) ba.playsound(ba.getsound('error')) pluglist = ba.app.potential_plugins plugstates: Dict[str, Dict] = ba.app.config.setdefault('Plugins', {}) assert isinstance(plugstates, dict) for i, availplug in enumerate(pluglist): active = availplug.class_path in ba.app.active_plugins plugstate = plugstates.setdefault(availplug.class_path, {}) checked = plugstate.get('enabled', False) assert isinstance(checked, bool) check = ba.checkboxwidget( parent=self._subcontainer, text=availplug.display_name, value=checked, maxwidth=self._scroll_width - 100, size=(self._scroll_width - 40, 50), on_value_change_call=ba.Call(self._check_value_changed, availplug), textcolor=((0.8, 0.3, 0.3) if not availplug.available else (0, 1, 0) if active else (0.6, 0.6, 0.6))) # Make sure we scroll all the way to the end when using # keyboard/button nav. ba.widget(edit=check, show_buffer_top=40, show_buffer_bottom=40) # Keep last from looping to back button when down is pressed. if i == len(pluglist) - 1: ba.widget(edit=check, down_widget=check) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) self._restore_state()
def __init__(self, sessiontype: Type[ba.Session], transition: Optional[str] = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=cyclic-import from bastd.ui.playlist import PlaylistTypeVars # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None # Store state for when we exit the next game. if issubclass(sessiontype, ba.DualTeamSession): ba.app.main_window = 'Team Game Select' ba.set_analytics_screen('Teams Window') elif issubclass(sessiontype, ba.FreeForAllSession): ba.app.main_window = 'Free-for-All Game Select' ba.set_analytics_screen('FreeForAll Window') else: raise TypeError(f'Invalid sessiontype: {sessiontype}.') self._pvars = PlaylistTypeVars(sessiontype) self._sessiontype = sessiontype self._customize_button: Optional[ba.Widget] = None self._sub_width: Optional[float] = None self._sub_height: Optional[float] = None # On new installations, go ahead and create a few playlists # besides the hard-coded default one: if not _ba.get_account_misc_val('madeStandardPlaylists', False): _ba.add_transaction({ 'type': 'ADD_PLAYLIST', 'playlistType': 'Free-for-All', 'playlistName': ba.Lstr( resource='singleGamePlaylistNameText').evaluate().replace( '${GAME}', ba.Lstr(translate=('gameNames', 'Death Match')).evaluate()), 'playlist': [ { 'type': 'bs_death_match.DeathMatchGame', 'settings': { 'Epic Mode': False, 'Kills to Win Per Player': 10, 'Respawn Times': 1.0, 'Time Limit': 300, 'map': 'Doom Shroom' } }, { 'type': 'bs_death_match.DeathMatchGame', 'settings': { 'Epic Mode': False, 'Kills to Win Per Player': 10, 'Respawn Times': 1.0, 'Time Limit': 300, 'map': 'Crag Castle' } }, ] }) _ba.add_transaction({ 'type': 'ADD_PLAYLIST', 'playlistType': 'Team Tournament', 'playlistName': ba.Lstr( resource='singleGamePlaylistNameText').evaluate().replace( '${GAME}', ba.Lstr(translate=('gameNames', 'Capture the Flag')).evaluate()), 'playlist': [ { 'type': 'bs_capture_the_flag.CTFGame', 'settings': { 'map': 'Bridgit', 'Score to Win': 3, 'Flag Idle Return Time': 30, 'Flag Touch Return Time': 0, 'Respawn Times': 1.0, 'Time Limit': 600, 'Epic Mode': False } }, { 'type': 'bs_capture_the_flag.CTFGame', 'settings': { 'map': 'Roundabout', 'Score to Win': 2, 'Flag Idle Return Time': 30, 'Flag Touch Return Time': 0, 'Respawn Times': 1.0, 'Time Limit': 600, 'Epic Mode': False } }, { 'type': 'bs_capture_the_flag.CTFGame', 'settings': { 'map': 'Tip Top', 'Score to Win': 2, 'Flag Idle Return Time': 30, 'Flag Touch Return Time': 3, 'Respawn Times': 1.0, 'Time Limit': 300, 'Epic Mode': False } }, ] }) _ba.add_transaction({ 'type': 'ADD_PLAYLIST', 'playlistType': 'Team Tournament', 'playlistName': ba.Lstr(translate=('playlistNames', 'Just Sports')).evaluate(), 'playlist': [ { 'type': 'bs_hockey.HockeyGame', 'settings': { 'Time Limit': 0, 'map': 'Hockey Stadium', 'Score to Win': 1, 'Respawn Times': 1.0 } }, { 'type': 'bs_football.FootballTeamGame', 'settings': { 'Time Limit': 0, 'map': 'Football Stadium', 'Score to Win': 21, 'Respawn Times': 1.0 } }, ] }) _ba.add_transaction({ 'type': 'ADD_PLAYLIST', 'playlistType': 'Free-for-All', 'playlistName': ba.Lstr(translate=('playlistNames', 'Just Epic')).evaluate(), 'playlist': [{ 'type': 'bs_elimination.EliminationGame', 'settings': { 'Time Limit': 120, 'map': 'Tip Top', 'Respawn Times': 1.0, 'Lives Per Player': 1, 'Epic Mode': 1 } }] }) _ba.add_transaction({ 'type': 'SET_MISC_VAL', 'name': 'madeStandardPlaylists', 'value': True }) _ba.run_transactions() # Get the current selection (if any). self._selected_playlist = ba.app.config.get(self._pvars.config_name + ' Playlist Selection') uiscale = ba.app.uiscale self._width = 900 if uiscale is ba.UIScale.SMALL else 800 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = (480 if uiscale is ba.UIScale.SMALL else 510 if uiscale is ba.UIScale.MEDIUM else 580) top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility='menu_full', scale_origin_stack_offset=scale_origin, scale=(1.69 if uiscale is ba.UIScale.SMALL else 1.05 if uiscale is ba.UIScale.MEDIUM else 0.9), stack_offset=(0, -26) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button: Optional[ba.Widget] = ba.buttonwidget( parent=self._root_widget, position=(59 + x_inset, self._height - 70), size=(120, 60), scale=1.0, on_activate_call=self._on_back_press, autoselect=True, label=ba.Lstr(resource='backText'), button_type='back') ba.containerwidget(edit=self._root_widget, cancel_button=self._back_button) txt = self._title_text = ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 41), size=(0, 0), text=self._pvars.window_title_name, scale=1.3, res_scale=1.5, color=ba.app.heading_color, h_align='center', v_align='center') if uiscale is ba.UIScale.SMALL and ba.app.toolbars: ba.textwidget(edit=txt, text='') ba.buttonwidget(edit=self._back_button, button_type='backSmall', size=(60, 54), position=(59 + x_inset, self._height - 67), label=ba.charstr(ba.SpecialChar.BACK)) if uiscale is ba.UIScale.SMALL and ba.app.toolbars: self._back_button.delete() self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._on_back_press) scroll_offs = 33 else: scroll_offs = 0 self._scroll_width = self._width - (100 + 2 * x_inset) self._scroll_height = self._height - ( 146 if uiscale is ba.UIScale.SMALL and ba.app.toolbars else 136) self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, size=(self._scroll_width, self._scroll_height), position=((self._width - self._scroll_width) * 0.5, 65 + scroll_offs)) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._subcontainer: Optional[ba.Widget] = None self._config_name_full = self._pvars.config_name + ' Playlists' self._last_config = None # Update now and once per second. # (this should do our initial refresh) self._update() self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True)
def __init__(self, transition: str = 'in_right', modal: bool = False, origin_widget: ba.Widget = None, close_once_signed_in: bool = False): # pylint: disable=too-many-statements self._sign_in_game_circle_button: Optional[ba.Widget] = None self._sign_in_v2_button: Optional[ba.Widget] = None self._sign_in_device_button: Optional[ba.Widget] = None self._close_once_signed_in = close_once_signed_in ba.set_analytics_screen('Account Window') # If they provided an origin-widget, scale up from that. scale_origin: Optional[tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'accountSettingsWindow' self._modal = modal self._needs_refresh = False self._signed_in = (_ba.get_v1_account_state() == 'signed_in') self._account_state_num = _ba.get_v1_account_state_num() self._show_linked = (self._signed_in and _ba.get_v1_account_misc_read_val( 'allowAccountLinking2', False)) self._check_sign_in_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) # Currently we can only reset achievements on game-center. account_type: Optional[str] if self._signed_in: account_type = _ba.get_v1_account_type() else: account_type = None self._can_reset_achievements = (account_type == 'Game Center') app = ba.app uiscale = app.ui.uiscale self._width = 760 if uiscale is ba.UIScale.SMALL else 660 x_offs = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = (390 if uiscale is ba.UIScale.SMALL else 430 if uiscale is ba.UIScale.MEDIUM else 490) self._sign_in_button = None self._sign_in_text = None self._scroll_width = self._width - (100 + x_offs * 2) self._scroll_height = self._height - 120 self._sub_width = self._scroll_width - 20 # Determine which sign-in/sign-out buttons we should show. self._show_sign_in_buttons: list[str] = [] if app.platform == 'android' and app.subplatform == 'google': self._show_sign_in_buttons.append('Google Play') elif app.platform == 'android' and app.subplatform == 'amazon': self._show_sign_in_buttons.append('Game Circle') # Local accounts are generally always available with a few key # exceptions. self._show_sign_in_buttons.append('Local') # Ditto with shiny new V2 ones. if bool(True): self._show_sign_in_buttons.append('V2') top_extra = 15 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=(2.09 if uiscale is ba.UIScale.SMALL else 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -19) if uiscale is ba.UIScale.SMALL else (0, 0))) if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) else: self._back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(51 + x_offs, self._height - 62), size=(120, 60), scale=0.8, text_scale=1.2, autoselect=True, label=ba.Lstr( resource='doneText' if self._modal else 'backText'), button_type='regular' if self._modal else 'back', on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) if not self._modal: ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 56), label=ba.charstr(ba.SpecialChar.BACK)) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 41), size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.ui.title_color, maxwidth=self._width - 340, h_align='center', v_align='center') self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, position=((self._width - self._scroll_width) * 0.5, self._height - 65 - self._scroll_height), size=(self._scroll_width, self._scroll_height), claims_left_right=True, claims_tab=True, selection_loops_to_parent=True) self._subcontainer: Optional[ba.Widget] = None self._refresh() self._restore_state()
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-locals # pylint: disable=too-many-branches # pylint: disable=too-many-statements from bastd.ui import popup from bastd.ui.config import ConfigCheckBox, ConfigNumberEdit # if they provided an origin-widget, scale up from that scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'graphicsSettingsWindow' app = ba.app spacing = 32 self._have_selected_child = False uiscale = app.ui.uiscale width = 450.0 height = 302.0 self._show_fullscreen = False fullscreen_spacing_top = spacing * 0.2 fullscreen_spacing = spacing * 1.2 if uiscale == ba.UIScale.LARGE and app.platform != 'android': self._show_fullscreen = True height += fullscreen_spacing + fullscreen_spacing_top show_gamma = False gamma_spacing = spacing * 1.3 if _ba.has_gamma_control(): show_gamma = True height += gamma_spacing show_vsync = False if app.platform == 'mac': show_vsync = True show_resolution = True if app.vr_mode: show_resolution = (app.platform == 'android' and app.subplatform == 'cardboard') uiscale = ba.app.ui.uiscale base_scale = (2.4 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) popup_menu_scale = base_scale * 1.2 v = height - 50 v -= spacing * 1.15 super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, scale_origin_stack_offset=scale_origin, scale=base_scale, stack_offset=(0, -30) if uiscale is ba.UIScale.SMALL else (0, 0))) btn = ba.buttonwidget(parent=self._root_widget, position=(35, height - 50), size=(120, 60), scale=0.8, text_scale=1.2, autoselect=True, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.textwidget(parent=self._root_widget, position=(0, height - 44), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.ui.title_color, h_align='center', v_align='top') ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) self._fullscreen_checkbox: Optional[ba.Widget] if self._show_fullscreen: v -= fullscreen_spacing_top self._fullscreen_checkbox = ConfigCheckBox( parent=self._root_widget, position=(100, v), maxwidth=200, size=(300, 30), configkey='Fullscreen', displayname=ba.Lstr(resource=self._r + ('.fullScreenCmdText' if app.platform == 'mac' else '.fullScreenCtrlText'))).widget if not self._have_selected_child: ba.containerwidget(edit=self._root_widget, selected_child=self._fullscreen_checkbox) self._have_selected_child = True v -= fullscreen_spacing else: self._fullscreen_checkbox = None self._gamma_controls: Optional[ConfigNumberEdit] if show_gamma: self._gamma_controls = gmc = ConfigNumberEdit( parent=self._root_widget, position=(90, v), configkey='Screen Gamma', displayname=ba.Lstr(resource=self._r + '.gammaText'), minval=0.1, maxval=2.0, increment=0.1, xoffset=-70, textscale=0.85) if ba.app.ui.use_toolbars: ba.widget(edit=gmc.plusbutton, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: ba.containerwidget(edit=self._root_widget, selected_child=gmc.minusbutton) self._have_selected_child = True v -= gamma_spacing else: self._gamma_controls = None self._selected_color = (0.5, 1, 0.5, 1) self._unselected_color = (0.7, 0.7, 0.7, 1) # quality ba.textwidget(parent=self._root_widget, position=(60, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.visualsText'), color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', v_align='center') popup.PopupMenu( parent=self._root_widget, position=(60, v - 50), width=150, scale=popup_menu_scale, choices=['Auto', 'Higher', 'High', 'Medium', 'Low'], choices_disabled=['Higher', 'High'] if _ba.get_max_graphics_quality() == 'Medium' else [], choices_display=[ ba.Lstr(resource='autoText'), ba.Lstr(resource=self._r + '.higherText'), ba.Lstr(resource=self._r + '.highText'), ba.Lstr(resource=self._r + '.mediumText'), ba.Lstr(resource=self._r + '.lowText') ], current_choice=ba.app.config.resolve('Graphics Quality'), on_value_change_call=self._set_quality) # texture controls ba.textwidget(parent=self._root_widget, position=(230, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.texturesText'), color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', v_align='center') textures_popup = popup.PopupMenu( parent=self._root_widget, position=(230, v - 50), width=150, scale=popup_menu_scale, choices=['Auto', 'High', 'Medium', 'Low'], choices_display=[ ba.Lstr(resource='autoText'), ba.Lstr(resource=self._r + '.highText'), ba.Lstr(resource=self._r + '.mediumText'), ba.Lstr(resource=self._r + '.lowText') ], current_choice=ba.app.config.resolve('Texture Quality'), on_value_change_call=self._set_textures) if ba.app.ui.use_toolbars: ba.widget(edit=textures_popup.get_button(), right_widget=_ba.get_special_widget('party_button')) v -= 80 h_offs = 0 if show_resolution: # resolution ba.textwidget(parent=self._root_widget, position=(h_offs + 60, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.resolutionText'), color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', v_align='center') # on standard android we have 'Auto', 'Native', and a few # HD standards if app.platform == 'android': # on cardboard/daydream android we have a few # render-target-scale options if app.subplatform == 'cardboard': current_res_cardboard = (str(min(100, max(10, int(round( ba.app.config.resolve('GVR Render Target Scale') * 100.0))))) + '%') # yapf: disable popup.PopupMenu( parent=self._root_widget, position=(h_offs + 60, v - 50), width=120, scale=popup_menu_scale, choices=['100%', '75%', '50%', '35%'], current_choice=current_res_cardboard, on_value_change_call=self._set_gvr_render_target_scale) else: native_res = _ba.get_display_resolution() assert native_res is not None choices = ['Auto', 'Native'] choices_display = [ ba.Lstr(resource='autoText'), ba.Lstr(resource='nativeText') ] for res in [1440, 1080, 960, 720, 480]: # nav bar is 72px so lets allow for that in what # choices we show if native_res[1] >= res - 72: res_str = str(res) + 'p' choices.append(res_str) choices_display.append(ba.Lstr(value=res_str)) current_res_android = ba.app.config.resolve( 'Resolution (Android)') popup.PopupMenu(parent=self._root_widget, position=(h_offs + 60, v - 50), width=120, scale=popup_menu_scale, choices=choices, choices_display=choices_display, current_choice=current_res_android, on_value_change_call=self._set_android_res) else: # if we're on a system that doesn't allow setting resolution, # set pixel-scale instead current_res = _ba.get_display_resolution() if current_res is None: current_res2 = (str(min(100, max(10, int(round( ba.app.config.resolve('Screen Pixel Scale') * 100.0))))) + '%') # yapf: disable popup.PopupMenu( parent=self._root_widget, position=(h_offs + 60, v - 50), width=120, scale=popup_menu_scale, choices=['100%', '88%', '75%', '63%', '50%'], current_choice=current_res2, on_value_change_call=self._set_pixel_scale) else: raise Exception('obsolete path; discrete resolutions' ' no longer supported') # vsync if show_vsync: ba.textwidget(parent=self._root_widget, position=(230, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.verticalSyncText'), color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', v_align='center') popup.PopupMenu( parent=self._root_widget, position=(230, v - 50), width=150, scale=popup_menu_scale, choices=['Auto', 'Always', 'Never'], choices_display=[ ba.Lstr(resource='autoText'), ba.Lstr(resource=self._r + '.alwaysText'), ba.Lstr(resource=self._r + '.neverText') ], current_choice=ba.app.config.resolve('Vertical Sync'), on_value_change_call=self._set_vsync) v -= 90 fpsc = ConfigCheckBox(parent=self._root_widget, position=(69, v - 6), size=(210, 30), scale=0.86, configkey='Show FPS', displayname=ba.Lstr(resource=self._r + '.showFPSText'), maxwidth=130) # (tv mode doesnt apply to vr) if not ba.app.vr_mode: tvc = ConfigCheckBox(parent=self._root_widget, position=(240, v - 6), size=(210, 30), scale=0.86, configkey='TV Border', displayname=ba.Lstr(resource=self._r + '.tvBorderText'), maxwidth=130) # grumble.. ba.widget(edit=fpsc.widget, right_widget=tvc.widget) try: pass except Exception: ba.print_exception('Exception wiring up graphics settings UI:') v -= spacing # make a timer to update our controls in case the config changes # under us self._update_timer = ba.Timer(0.25, ba.WeakCall(self._update_controls), repeat=True, timetype=ba.TimeType.REAL)
def __init__(self, sessiontype: Type[ba.Session], transition: str = 'in_right', select_playlist: str = None, origin_widget: ba.Widget = None): # Yes this needs tidying. # pylint: disable=too-many-locals # pylint: disable=too-many-statements # pylint: disable=cyclic-import from bastd.ui import playlist scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._sessiontype = sessiontype self._pvars = playlist.PlaylistTypeVars(sessiontype) self._max_playlists = 30 self._r = 'gameListWindow' self._width = 750.0 if ba.app.small_ui else 650.0 x_inset = 50.0 if ba.app.small_ui else 0.0 self._height = (380.0 if ba.app.small_ui else 420.0 if ba.app.med_ui else 500.0) top_extra = 20.0 if ba.app.small_ui else 0.0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, scale_origin_stack_offset=scale_origin, scale=(2.05 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0), stack_offset=(0, -10) if ba.app.small_ui else (0, 0))) self._back_button = back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(43 + x_inset, self._height - 60), size=(160, 68), scale=0.77, autoselect=True, text_scale=1.3, label=ba.Lstr(resource='backText'), button_type='back') ba.textwidget(parent=self._root_widget, position=(0, self._height - 47), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText', subs=[('${TYPE}', self._pvars.window_title_name)]), color=ba.app.heading_color, maxwidth=290, h_align='center', v_align='center') ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) v = self._height - 59.0 h = 41 + x_inset b_color = (0.6, 0.53, 0.63) b_textcolor = (0.75, 0.7, 0.8) self._lock_images: List[ba.Widget] = [] lock_tex = ba.gettexture('lock') scl = (1.1 if ba.app.small_ui else 1.27 if ba.app.med_ui else 1.57) scl *= 0.63 v -= 65.0 * scl new_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(90, 58.0 * scl), on_activate_call=self._new_playlist, color=b_color, autoselect=True, button_type='square', textcolor=b_textcolor, text_scale=0.7, label=ba.Lstr(resource='newText', fallback_resource=self._r + '.newText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 58.0 * scl - 28), texture=lock_tex)) v -= 65.0 * scl self._edit_button = edit_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(90, 58.0 * scl), on_activate_call=self._edit_playlist, color=b_color, autoselect=True, textcolor=b_textcolor, button_type='square', text_scale=0.7, label=ba.Lstr(resource='editText', fallback_resource=self._r + '.editText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 58.0 * scl - 28), texture=lock_tex)) v -= 65.0 * scl duplicate_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(90, 58.0 * scl), on_activate_call=self._duplicate_playlist, color=b_color, autoselect=True, textcolor=b_textcolor, button_type='square', text_scale=0.7, label=ba.Lstr(resource='duplicateText', fallback_resource=self._r + '.duplicateText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 58.0 * scl - 28), texture=lock_tex)) v -= 65.0 * scl delete_button = btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(90, 58.0 * scl), on_activate_call=self._delete_playlist, color=b_color, autoselect=True, textcolor=b_textcolor, button_type='square', text_scale=0.7, label=ba.Lstr(resource='deleteText', fallback_resource=self._r + '.deleteText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 58.0 * scl - 28), texture=lock_tex)) v -= 65.0 * scl self._import_button = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(90, 58.0 * scl), on_activate_call=self._import_playlist, color=b_color, autoselect=True, textcolor=b_textcolor, button_type='square', text_scale=0.7, label=ba.Lstr(resource='importText')) v -= 65.0 * scl btn = ba.buttonwidget(parent=self._root_widget, position=(h, v), size=(90, 58.0 * scl), on_activate_call=self._share_playlist, color=b_color, autoselect=True, textcolor=b_textcolor, button_type='square', text_scale=0.7, label=ba.Lstr(resource='shareText')) self._lock_images.append( ba.imagewidget(parent=self._root_widget, size=(30, 30), draw_controller=btn, position=(h - 10, v + 58.0 * scl - 28), texture=lock_tex)) v = self._height - 75 self._scroll_height = self._height - 119 scrollwidget = ba.scrollwidget(parent=self._root_widget, position=(140 + x_inset, v - self._scroll_height), size=(self._width - (180 + 2 * x_inset), self._scroll_height + 10), highlight=False) ba.widget(edit=back_button, right_widget=scrollwidget) self._columnwidget = ba.columnwidget(parent=scrollwidget) h = 145 try: self._do_randomize_val = ba.app.config[self._pvars.config_name + ' Playlist Randomize'] except Exception: self._do_randomize_val = 0 h += 210 for btn in [new_button, delete_button, edit_button, duplicate_button]: ba.widget(edit=btn, right_widget=scrollwidget) ba.widget(edit=scrollwidget, left_widget=new_button, right_widget=_ba.get_special_widget('party_button') if ba.app.toolbars else None) # make sure config exists self._config_name_full = self._pvars.config_name + ' Playlists' if self._config_name_full not in ba.app.config: ba.app.config[self._config_name_full] = {} self._selected_playlist_name: Optional[str] = None self._selected_playlist_index: Optional[int] = None self._playlist_widgets: List[ba.Widget] = [] self._refresh(select_playlist=select_playlist) ba.buttonwidget(edit=back_button, on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=back_button) ba.containerwidget(edit=self._root_widget, selected_child=scrollwidget) # Keep our lock images up to date/etc. self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) self._update()
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals import threading # Preload some modules we use in a background thread so we won't # have a visual hitch when the user taps them. threading.Thread(target=self._preload_modules).start() # We can currently be used either for main menu duty or for selecting # playlists (should make this more elegant/general). self._is_main_menu = not ba.app.ui.selecting_private_party_playlist uiscale = ba.app.ui.uiscale width = 1000 if uiscale is ba.UIScale.SMALL else 800 x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 height = 550 button_width = 400 scale_origin: Optional[tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'playWindow' super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_full', scale_origin_stack_offset=scale_origin, scale=(1.6 if uiscale is ba.UIScale.SMALL else 0.9 if uiscale is ba.UIScale.MEDIUM else 0.8), stack_offset=(0, 0) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(55 + x_offs, height - 132), size=(120, 60), scale=1.1, text_res_scale=1.5, text_scale=1.2, autoselect=True, label=ba.Lstr(resource='backText'), button_type='back') txt = ba.textwidget( parent=self._root_widget, position=(width * 0.5, height - 101), # position=(width * 0.5, height - # (101 if main_menu else 61)), size=(0, 0), text=ba.Lstr(resource=( self._r + '.titleText') if self._is_main_menu else 'playlistsText'), scale=1.7, res_scale=2.0, maxwidth=400, color=ba.app.ui.heading_color, h_align='center', v_align='center') ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.textwidget(edit=txt, text='') v = height - (110 if self._is_main_menu else 90) v -= 100 clr = (0.6, 0.7, 0.6, 1.0) v -= 280 if self._is_main_menu else 180 v += (30 if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL else 0) hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100 scl = 1.13 if self._is_main_menu else 0.68 self._lineup_tex = ba.gettexture('playerLineup') angry_computer_transparent_model = ba.getmodel( 'angryComputerTransparent') self._lineup_1_transparent_model = ba.getmodel( 'playerLineup1Transparent') self._lineup_2_transparent_model = ba.getmodel( 'playerLineup2Transparent') self._lineup_3_transparent_model = ba.getmodel( 'playerLineup3Transparent') self._lineup_4_transparent_model = ba.getmodel( 'playerLineup4Transparent') self._eyes_model = ba.getmodel('plasticEyesTransparent') self._coop_button: Optional[ba.Widget] = None # Only show coop button in main-menu variant. if self._is_main_menu: self._coop_button = btn = ba.buttonwidget( parent=self._root_widget, position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)), size=(scl * button_width, scl * (300 if self._is_main_menu else 360)), extra_touch_border_scale=0.1, autoselect=True, label='', button_type='square', text_scale=1.13, on_activate_call=self._coop) if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) ba.widget(edit=btn, up_widget=_ba.get_special_widget('account_button')) ba.widget( edit=btn, down_widget=_ba.get_special_widget('settings_button')) self._draw_dude(0, btn, hoffs, v, scl, position=(140, 30), color=(0.72, 0.4, 1.0)) self._draw_dude(1, btn, hoffs, v, scl, position=(185, 53), color=(0.71, 0.5, 1.0)) self._draw_dude(2, btn, hoffs, v, scl, position=(220, 27), color=(0.67, 0.44, 1.0)) self._draw_dude(3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)) ba.imagewidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * 230, v + scl * 153), size=(scl * 115, scl * 115), texture=self._lineup_tex, model_transparent=angry_computer_transparent_model) ba.textwidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * (-10), v + scl * 95), size=(scl * button_width, scl * 50), text=ba.Lstr( resource='playModes.singlePlayerCoopText', fallback_resource='playModes.coopText'), maxwidth=scl * button_width * 0.7, res_scale=1.5, h_align='center', v_align='center', color=(0.7, 0.9, 0.7, 1.0), scale=scl * 2.3) ba.textwidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * (-10), v + (scl * 54)), size=(scl * button_width, scl * 30), text=ba.Lstr(resource=self._r + '.oneToFourPlayersText'), h_align='center', v_align='center', scale=0.83 * scl, flatness=1.0, maxwidth=scl * button_width * 0.7, color=clr) scl = 0.5 if self._is_main_menu else 0.68 hoffs += 440 if self._is_main_menu else 216 v += 180 if self._is_main_menu else -68 self._teams_button = btn = ba.buttonwidget( parent=self._root_widget, position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)), size=(scl * button_width, scl * (300 if self._is_main_menu else 360)), extra_touch_border_scale=0.1, autoselect=True, label='', button_type='square', text_scale=1.13, on_activate_call=self._team_tourney) if ba.app.ui.use_toolbars: ba.widget(edit=btn, up_widget=_ba.get_special_widget('tickets_plus_button'), right_widget=_ba.get_special_widget('party_button')) xxx = -14 self._draw_dude(2, btn, hoffs, v, scl, position=(xxx + 148, 30), color=(0.2, 0.4, 1.0)) self._draw_dude(3, btn, hoffs, v, scl, position=(xxx + 181, 53), color=(0.3, 0.4, 1.0)) self._draw_dude(1, btn, hoffs, v, scl, position=(xxx + 216, 33), color=(0.3, 0.5, 1.0)) self._draw_dude(0, btn, hoffs, v, scl, position=(xxx + 245, 57), color=(0.3, 0.5, 1.0)) xxx = 155 self._draw_dude(0, btn, hoffs, v, scl, position=(xxx + 151, 30), color=(1.0, 0.5, 0.4)) self._draw_dude(1, btn, hoffs, v, scl, position=(xxx + 189, 53), color=(1.0, 0.58, 0.58)) self._draw_dude(3, btn, hoffs, v, scl, position=(xxx + 223, 27), color=(1.0, 0.5, 0.5)) self._draw_dude(2, btn, hoffs, v, scl, position=(xxx + 257, 57), color=(1.0, 0.5, 0.5)) ba.textwidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * (-10), v + scl * 95), size=(scl * button_width, scl * 50), text=ba.Lstr(resource='playModes.teamsText', fallback_resource='teamsText'), res_scale=1.5, maxwidth=scl * button_width * 0.7, h_align='center', v_align='center', color=(0.7, 0.9, 0.7, 1.0), scale=scl * 2.3) ba.textwidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * (-10), v + (scl * 54)), size=(scl * button_width, scl * 30), text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'), h_align='center', v_align='center', res_scale=1.5, scale=0.9 * scl, flatness=1.0, maxwidth=scl * button_width * 0.7, color=clr) hoffs += 0 if self._is_main_menu else 300 v -= 155 if self._is_main_menu else 0 self._free_for_all_button = btn = ba.buttonwidget( parent=self._root_widget, position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)), size=(scl * button_width, scl * (300 if self._is_main_menu else 360)), extra_touch_border_scale=0.1, autoselect=True, label='', button_type='square', text_scale=1.13, on_activate_call=self._free_for_all) xxx = -5 self._draw_dude(0, btn, hoffs, v, scl, position=(xxx + 140, 30), color=(0.4, 1.0, 0.4)) self._draw_dude(3, btn, hoffs, v, scl, position=(xxx + 185, 53), color=(1.0, 0.4, 0.5)) self._draw_dude(1, btn, hoffs, v, scl, position=(xxx + 220, 27), color=(0.4, 0.5, 1.0)) self._draw_dude(2, btn, hoffs, v, scl, position=(xxx + 255, 57), color=(0.5, 1.0, 0.4)) xxx = 140 self._draw_dude(2, btn, hoffs, v, scl, position=(xxx + 148, 30), color=(1.0, 0.9, 0.4)) self._draw_dude(0, btn, hoffs, v, scl, position=(xxx + 182, 53), color=(0.7, 1.0, 0.5)) self._draw_dude(3, btn, hoffs, v, scl, position=(xxx + 233, 27), color=(0.7, 0.5, 0.9)) self._draw_dude(1, btn, hoffs, v, scl, position=(xxx + 266, 53), color=(0.4, 0.5, 0.8)) ba.textwidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * (-10), v + scl * 95), size=(scl * button_width, scl * 50), text=ba.Lstr(resource='playModes.freeForAllText', fallback_resource='freeForAllText'), maxwidth=scl * button_width * 0.7, h_align='center', v_align='center', color=(0.7, 0.9, 0.7, 1.0), scale=scl * 1.9) ba.textwidget(parent=self._root_widget, draw_controller=btn, position=(hoffs + scl * (-10), v + (scl * 54)), size=(scl * button_width, scl * 30), text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'), h_align='center', v_align='center', scale=0.9 * scl, flatness=1.0, maxwidth=scl * button_width * 0.7, color=clr) if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: back_button.delete() ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back, selected_child=self._coop_button if self._is_main_menu else self._teams_button) else: ba.buttonwidget(edit=back_button, on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=back_button, selected_child=self._coop_button if self._is_main_menu else self._teams_button) self._restore_state()
def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals import threading # Preload some modules we use in a background thread so we won't # have a visual hitch when the user taps them. threading.Thread(target=self._preload_modules).start() ba.set_analytics_screen('Settings Window') scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None uiscale = ba.app.uiscale width = 900 if uiscale is ba.UIScale.SMALL else 580 x_inset = 75 if uiscale is ba.UIScale.SMALL else 0 height = 435 # button_height = 42 self._r = 'settingsWindow' top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, scale=(1.75 if uiscale is ba.UIScale.SMALL else 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -8) if uiscale is ba.UIScale.SMALL else (0, 0))) if ba.app.toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._do_back) else: self._back_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(40 + x_inset, height - 55), size=(130, 60), scale=0.8, text_scale=1.2, label=ba.Lstr(resource='backText'), button_type='back', on_activate_call=self._do_back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.textwidget(parent=self._root_widget, position=(0, height - 44), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.title_color, h_align='center', v_align='center', maxwidth=130) if self._back_button is not None: ba.buttonwidget(edit=self._back_button, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) v = height - 80 v -= 145 basew = 280 if uiscale is ba.UIScale.SMALL else 230 baseh = 170 x_offs = x_inset + (105 if uiscale is ba.UIScale.SMALL else 72) - basew # now unused x_offs2 = x_offs + basew - 7 x_offs3 = x_offs + 2 * (basew - 7) x_offs4 = x_offs2 x_offs5 = x_offs3 def _b_title(x: float, y: float, button: ba.Widget, text: Union[str, ba.Lstr]) -> None: ba.textwidget(parent=self._root_widget, text=text, position=(x + basew * 0.47, y + baseh * 0.22), maxwidth=basew * 0.7, size=(0, 0), h_align='center', v_align='center', draw_controller=button, color=(0.7, 0.9, 0.7, 1.0)) ctb = self._controllers_button = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(x_offs2, v), size=(basew, baseh), button_type='square', label='', on_activate_call=self._do_controllers) if ba.app.toolbars and self._back_button is None: bbtn = _ba.get_special_widget('back_button') ba.widget(edit=ctb, left_widget=bbtn) _b_title(x_offs2, v, ctb, ba.Lstr(resource=self._r + '.controllersText')) imgw = imgh = 130 ba.imagewidget(parent=self._root_widget, position=(x_offs2 + basew * 0.49 - imgw * 0.5, v + 35), size=(imgw, imgh), texture=ba.gettexture('controllerIcon'), draw_controller=ctb) gfxb = self._graphics_button = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(x_offs3, v), size=(basew, baseh), button_type='square', label='', on_activate_call=self._do_graphics) if ba.app.toolbars: pbtn = _ba.get_special_widget('party_button') ba.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn) _b_title(x_offs3, v, gfxb, ba.Lstr(resource=self._r + '.graphicsText')) imgw = imgh = 110 ba.imagewidget(parent=self._root_widget, position=(x_offs3 + basew * 0.49 - imgw * 0.5, v + 42), size=(imgw, imgh), texture=ba.gettexture('graphicsIcon'), draw_controller=gfxb) v -= (baseh - 5) abtn = self._audio_button = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(x_offs4, v), size=(basew, baseh), button_type='square', label='', on_activate_call=self._do_audio) _b_title(x_offs4, v, abtn, ba.Lstr(resource=self._r + '.audioText')) imgw = imgh = 120 ba.imagewidget(parent=self._root_widget, position=(x_offs4 + basew * 0.49 - imgw * 0.5 + 5, v + 35), size=(imgw, imgh), color=(1, 1, 0), texture=ba.gettexture('audioIcon'), draw_controller=abtn) avb = self._advanced_button = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(x_offs5, v), size=(basew, baseh), button_type='square', label='', on_activate_call=self._do_advanced) _b_title(x_offs5, v, avb, ba.Lstr(resource=self._r + '.advancedText')) imgw = imgh = 120 ba.imagewidget(parent=self._root_widget, position=(x_offs5 + basew * 0.49 - imgw * 0.5 + 5, v + 35), size=(imgw, imgh), color=(0.8, 0.95, 1), texture=ba.gettexture('advancedIcon'), draw_controller=avb)
def safe_delete(widget: ba.Widget) -> None: if widget: widget.delete()
def __init__(self, origin_widget: ba.Widget = None): scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None transition = 'in_right' bg_color = (0.4, 0.4, 0.5) self._width = 560 self._height = 420 uiscale = ba.app.uiscale base_scale = (1.65 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, position=(40, self._height - 45), size=(50, 50), scale=0.7, label='', color=bg_color, on_activate_call=self._cancel, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) maxlinks = _ba.get_account_misc_read_val('maxLinkAccounts', 5) ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.56), size=(0, 0), text=ba.Lstr(resource=( 'accountSettingsWindow.linkAccountsInstructionsNewText'), subs=[('${COUNT}', str(maxlinks))]), maxwidth=self._width * 0.9, color=ba.app.infotextcolor, max_height=self._height * 0.6, h_align='center', v_align='center') ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) ba.buttonwidget( parent=self._root_widget, position=(40, 30), size=(200, 60), label=ba.Lstr( resource='accountSettingsWindow.linkAccountsGenerateCodeText'), autoselect=True, on_activate_call=self._generate_press) self._enter_code_button = ba.buttonwidget( parent=self._root_widget, position=(self._width - 240, 30), size=(200, 60), label=ba.Lstr( resource='accountSettingsWindow.linkAccountsEnterCodeText'), autoselect=True, on_activate_call=self._enter_code_press)
def __init__(self, transition: str = 'in_right', from_modal_store: bool = False, modal: bool = False, origin_widget: ba.Widget = None, store_back_location: str = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals ba.set_analytics_screen('Get Tickets Window') self._transitioning_out = False self._store_back_location = store_back_location # ew. self._ad_button_greyed = False self._smooth_update_timer: Optional[ba.Timer] = None self._ad_button = None self._ad_label = None self._ad_image = None self._ad_time_text = None # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None uiscale = ba.app.uiscale self._width = 1000.0 if uiscale is ba.UIScale.SMALL else 800.0 x_inset = 100.0 if uiscale is ba.UIScale.SMALL else 0.0 self._height = 480.0 self._modal = modal self._from_modal_store = from_modal_store self._r = 'getTicketsWindow' top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, scale_origin_stack_offset=scale_origin, color=(0.4, 0.37, 0.55), scale=(1.63 if uiscale is ba.UIScale.SMALL else 1.2 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -3) if uiscale is ba.UIScale.SMALL else (0, 0))) btn = ba.buttonwidget( parent=self._root_widget, position=(55 + x_inset, self._height - 79), size=(140, 60), scale=1.0, autoselect=True, label=ba.Lstr(resource='doneText' if modal else 'backText'), button_type='regular' if modal else 'back', on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 55), size=(0, 0), color=ba.app.title_color, scale=1.2, h_align='center', v_align='center', text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=290) if not modal: ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) b_size = (220.0, 180.0) v = self._height - b_size[1] - 80 spacing = 1 self._ad_button = None def _add_button(item: str, position: Tuple[float, float], size: Tuple[float, float], label: ba.Lstr, price: str = None, tex_name: str = None, tex_opacity: float = 1.0, tex_scale: float = 1.0, enabled: bool = True, text_scale: float = 1.0) -> ba.Widget: btn2 = ba.buttonwidget( parent=self._root_widget, position=position, button_type='square', size=size, label='', autoselect=True, color=None if enabled else (0.5, 0.5, 0.5), on_activate_call=(ba.Call(self._purchase, item) if enabled else self._disabled_press)) txt = ba.textwidget(parent=self._root_widget, text=label, position=(position[0] + size[0] * 0.5, position[1] + size[1] * 0.3), scale=text_scale, maxwidth=size[0] * 0.75, size=(0, 0), h_align='center', v_align='center', draw_controller=btn2, color=(0.7, 0.9, 0.7, 1.0 if enabled else 0.2)) if price is not None and enabled: ba.textwidget(parent=self._root_widget, text=price, position=(position[0] + size[0] * 0.5, position[1] + size[1] * 0.17), scale=0.7, maxwidth=size[0] * 0.75, size=(0, 0), h_align='center', v_align='center', draw_controller=btn2, color=(0.4, 0.9, 0.4, 1.0)) i = None if tex_name is not None: tex_size = 90.0 * tex_scale i = ba.imagewidget( parent=self._root_widget, texture=ba.gettexture(tex_name), position=(position[0] + size[0] * 0.5 - tex_size * 0.5, position[1] + size[1] * 0.66 - tex_size * 0.5), size=(tex_size, tex_size), draw_controller=btn2, opacity=tex_opacity * (1.0 if enabled else 0.25)) if item == 'ad': self._ad_button = btn2 self._ad_label = txt assert i is not None self._ad_image = i self._ad_time_text = ba.textwidget( parent=self._root_widget, text='1m 10s', position=(position[0] + size[0] * 0.5, position[1] + size[1] * 0.5), scale=text_scale * 1.2, maxwidth=size[0] * 0.85, size=(0, 0), h_align='center', v_align='center', draw_controller=btn2, color=(0.4, 0.9, 0.4, 1.0)) return btn2 rsrc = self._r + '.ticketsText' c2txt = ba.Lstr( resource=rsrc, subs=[('${COUNT}', str(_ba.get_account_misc_read_val('tickets2Amount', 500)))]) c3txt = ba.Lstr( resource=rsrc, subs=[('${COUNT}', str(_ba.get_account_misc_read_val('tickets3Amount', 1500)))]) c4txt = ba.Lstr( resource=rsrc, subs=[('${COUNT}', str(_ba.get_account_misc_read_val('tickets4Amount', 5000)))]) c5txt = ba.Lstr( resource=rsrc, subs=[('${COUNT}', str(_ba.get_account_misc_read_val('tickets5Amount', 15000)))]) h = 110.0 # enable buttons if we have prices.. tickets2_price = _ba.get_price('tickets2') tickets3_price = _ba.get_price('tickets3') tickets4_price = _ba.get_price('tickets4') tickets5_price = _ba.get_price('tickets5') # TEMP # tickets1_price = '$0.99' # tickets2_price = '$4.99' # tickets3_price = '$9.99' # tickets4_price = '$19.99' # tickets5_price = '$49.99' _add_button('tickets2', enabled=(tickets2_price is not None), position=(self._width * 0.5 - spacing * 1.5 - b_size[0] * 2.0 + h, v), size=b_size, label=c2txt, price=tickets2_price, tex_name='ticketsMore') # 0.99-ish _add_button('tickets3', enabled=(tickets3_price is not None), position=(self._width * 0.5 - spacing * 0.5 - b_size[0] * 1.0 + h, v), size=b_size, label=c3txt, price=tickets3_price, tex_name='ticketRoll') # 4.99-ish v -= b_size[1] - 5 _add_button('tickets4', enabled=(tickets4_price is not None), position=(self._width * 0.5 - spacing * 1.5 - b_size[0] * 2.0 + h, v), size=b_size, label=c4txt, price=tickets4_price, tex_name='ticketRollBig', tex_scale=1.2) # 9.99-ish _add_button('tickets5', enabled=(tickets5_price is not None), position=(self._width * 0.5 - spacing * 0.5 - b_size[0] * 1.0 + h, v), size=b_size, label=c5txt, price=tickets5_price, tex_name='ticketRolls', tex_scale=1.2) # 19.99-ish self._enable_ad_button = _ba.has_video_ads() h = self._width * 0.5 + 110.0 v = self._height - b_size[1] - 115.0 if self._enable_ad_button: h_offs = 35 b_size_3 = (150, 120) cdb = _add_button( 'ad', position=(h + h_offs, v), size=b_size_3, label=ba.Lstr(resource=self._r + '.ticketsFromASponsorText', subs=[('${COUNT}', str( _ba.get_account_misc_read_val( 'sponsorTickets', 5)))]), tex_name='ticketsMore', enabled=self._enable_ad_button, tex_opacity=0.6, tex_scale=0.7, text_scale=0.7) ba.buttonwidget(edit=cdb, color=(0.65, 0.5, 0.7) if self._enable_ad_button else (0.5, 0.5, 0.5)) self._ad_free_text = ba.textwidget( parent=self._root_widget, text=ba.Lstr(resource=self._r + '.freeText'), position=(h + h_offs + b_size_3[0] * 0.5, v + b_size_3[1] * 0.5 + 25), size=(0, 0), color=(1, 1, 0, 1.0) if self._enable_ad_button else (1, 1, 1, 0.2), draw_controller=cdb, rotate=15, shadow=1.0, maxwidth=150, h_align='center', v_align='center', scale=1.0) v -= 125 else: v -= 20 if True: # pylint: disable=using-constant-test h_offs = 35 b_size_3 = (150, 120) cdb = _add_button( 'app_invite', position=(h + h_offs, v), size=b_size_3, label=ba.Lstr( resource='gatherWindow.earnTicketsForRecommendingText', subs=[ ('${COUNT}', str(_ba.get_account_misc_read_val( 'sponsorTickets', 5))) ]), tex_name='ticketsMore', enabled=True, tex_opacity=0.6, tex_scale=0.7, text_scale=0.7) ba.buttonwidget(edit=cdb, color=(0.65, 0.5, 0.7)) ba.textwidget(parent=self._root_widget, text=ba.Lstr(resource=self._r + '.freeText'), position=(h + h_offs + b_size_3[0] * 0.5, v + b_size_3[1] * 0.5 + 25), size=(0, 0), color=(1, 1, 0, 1.0), draw_controller=cdb, rotate=15, shadow=1.0, maxwidth=150, h_align='center', v_align='center', scale=1.0) tc_y_offs = 0 h = self._width - (185 + x_inset) v = self._height - 95 + tc_y_offs txt1 = (ba.Lstr( resource=self._r + '.youHaveText').evaluate().split('${COUNT}')[0].strip()) txt2 = (ba.Lstr( resource=self._r + '.youHaveText').evaluate().split('${COUNT}')[-1].strip()) ba.textwidget(parent=self._root_widget, text=txt1, position=(h, v), size=(0, 0), color=(0.5, 0.5, 0.6), maxwidth=200, h_align='center', v_align='center', scale=0.8) v -= 30 self._ticket_count_text = ba.textwidget(parent=self._root_widget, position=(h, v), size=(0, 0), color=(0.2, 1.0, 0.2), maxwidth=200, h_align='center', v_align='center', scale=1.6) v -= 30 ba.textwidget(parent=self._root_widget, text=txt2, position=(h, v), size=(0, 0), color=(0.5, 0.5, 0.6), maxwidth=200, h_align='center', v_align='center', scale=0.8) # update count now and once per second going forward.. self._ticking_node: Optional[ba.Node] = None self._smooth_ticket_count: Optional[float] = None self._ticket_count = 0 self._update() self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) self._smooth_increase_speed = 1.0
def __init__(self, transition: str = 'in_right', modal: bool = False, show_tab: str = None, on_close_call: Callable[[], Any] = None, back_location: str = None, origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals from bastd.ui import tabs from ba import SpecialChar app = ba.app uiscale = app.uiscale ba.set_analytics_screen('Store Window') scale_origin: Optional[Tuple[float, float]] # If they provided an origin-widget, scale up from that. if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self.button_infos: Optional[Dict[str, Dict[str, Any]]] = None self.update_buttons_timer: Optional[ba.Timer] = None self._status_textwidget_update_timer = None self._back_location = back_location self._on_close_call = on_close_call self._show_tab = show_tab self._modal = modal self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (578 if uiscale is ba.UIScale.SMALL else 645 if uiscale is ba.UIScale.MEDIUM else 800) self._current_tab: Optional[str] = None extra_top = 30 if uiscale is ba.UIScale.SMALL else 0 self._request: Any = None self._r = 'store' self._last_buy_time: Optional[float] = None super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + extra_top), transition=transition, toolbar_visibility='menu_full', scale=(1.3 if uiscale is ba.UIScale.SMALL else 0.9 if uiscale is ba.UIScale.MEDIUM else 0.8), scale_origin_stack_offset=scale_origin, stack_offset=((0, -5) if uiscale is ba.UIScale.SMALL else ( 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0)))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(70 + x_inset, self._height - 74), size=(140, 60), scale=1.1, autoselect=True, label=ba.Lstr(resource='doneText' if self._modal else 'backText'), button_type=None if self._modal else 'back', on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) self._get_tickets_button = ba.buttonwidget( parent=self._root_widget, size=(210, 65), on_activate_call=self._on_get_more_tickets_press, autoselect=True, scale=0.9, text_scale=1.4, left_widget=self._back_button, color=(0.7, 0.5, 0.85), textcolor=(0.2, 1.0, 0.2), label=ba.Lstr(resource='getTicketsWindow.titleText')) # Move this dynamically to keep it out of the way of the party icon. self._update_get_tickets_button_pos() self._get_ticket_pos_update_timer = ba.Timer( 1.0, ba.WeakCall(self._update_get_tickets_button_pos), repeat=True, timetype=ba.TimeType.REAL) ba.widget(edit=self._back_button, right_widget=self._get_tickets_button) self._ticket_text_update_timer = ba.Timer( 1.0, ba.WeakCall(self._update_tickets_text), timetype=ba.TimeType.REAL, repeat=True) self._update_tickets_text() app = ba.app if app.platform in ['mac', 'ios'] and app.subplatform == 'appstore': ba.buttonwidget( parent=self._root_widget, position=(self._width * 0.5 - 70, 16), size=(230, 50), scale=0.65, on_activate_call=ba.WeakCall(self._restore_purchases), color=(0.35, 0.3, 0.4), selectable=False, textcolor=(0.55, 0.5, 0.6), label=ba.Lstr( resource='getTicketsWindow.restorePurchasesText')) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 44), size=(0, 0), color=app.title_color, scale=1.5, h_align='center', v_align='center', text=ba.Lstr(resource='storeText'), maxwidth=420) if not self._modal: ba.buttonwidget(edit=self._back_button, button_type='backSmall', size=(60, 60), label=ba.charstr(SpecialChar.BACK)) scroll_buffer_h = 130 + 2 * x_inset tab_buffer_h = 250 + 2 * x_inset tabs_def = [ ('extras', ba.Lstr(resource=self._r + '.extrasText')), ('maps', ba.Lstr(resource=self._r + '.mapsText')), ('minigames', ba.Lstr(resource=self._r + '.miniGamesText')), ('characters', ba.Lstr(resource=self._r + '.charactersText')), ('icons', ba.Lstr(resource=self._r + '.iconsText')), ] tab_results = tabs.create_tab_buttons(self._root_widget, tabs_def, pos=(tab_buffer_h * 0.5, self._height - 130), size=(self._width - tab_buffer_h, 50), on_select_call=self._set_tab, return_extra_info=True) self._purchasable_count_widgets: Dict[str, Dict[str, Any]] = {} # Create our purchasable-items tags and have them update over time. for i, tab in enumerate(tabs_def): pos = tab_results['positions'][i] size = tab_results['sizes'][i] button = tab_results['buttons_indexed'][i] rad = 10 center = (pos[0] + 0.1 * size[0], pos[1] + 0.9 * size[1]) img = ba.imagewidget(parent=self._root_widget, position=(center[0] - rad * 1.04, center[1] - rad * 1.15), size=(rad * 2.2, rad * 2.2), texture=ba.gettexture('circleShadow'), color=(1, 0, 0)) txt = ba.textwidget(parent=self._root_widget, position=center, size=(0, 0), h_align='center', v_align='center', maxwidth=1.4 * rad, scale=0.6, shadow=1.0, flatness=1.0) rad = 20 sale_img = ba.imagewidget(parent=self._root_widget, position=(center[0] - rad, center[1] - rad), size=(rad * 2, rad * 2), draw_controller=button, texture=ba.gettexture('circleZigZag'), color=(0.5, 0, 1.0)) sale_title_text = ba.textwidget(parent=self._root_widget, position=(center[0], center[1] + 0.24 * rad), size=(0, 0), h_align='center', v_align='center', draw_controller=button, maxwidth=1.4 * rad, scale=0.6, shadow=0.0, flatness=1.0, color=(0, 1, 0)) sale_time_text = ba.textwidget(parent=self._root_widget, position=(center[0], center[1] - 0.29 * rad), size=(0, 0), h_align='center', v_align='center', draw_controller=button, maxwidth=1.4 * rad, scale=0.4, shadow=0.0, flatness=1.0, color=(0, 1, 0)) self._purchasable_count_widgets[tab[0]] = { 'img': img, 'text': txt, 'sale_img': sale_img, 'sale_title_text': sale_title_text, 'sale_time_text': sale_time_text } self._tab_update_timer = ba.Timer(1.0, ba.WeakCall(self._update_tabs), timetype=ba.TimeType.REAL, repeat=True) self._update_tabs() self._tab_buttons = tab_results['buttons'] if self._get_tickets_button is not None: last_tab_button = self._tab_buttons[tabs_def[-1][0]] ba.widget(edit=self._get_tickets_button, down_widget=last_tab_button) ba.widget(edit=last_tab_button, up_widget=self._get_tickets_button, right_widget=self._get_tickets_button) self._scroll_width = self._width - scroll_buffer_h self._scroll_height = self._height - 180 self._scrollwidget: Optional[ba.Widget] = None self._status_textwidget: Optional[ba.Widget] = None self._restore_state()
def __init__(self, transition: str = 'in_right', in_main_menu: bool = True, selected_profile: str = None, origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals from ba.internal import ensure_have_account_player_profile self._in_main_menu = in_main_menu if self._in_main_menu: back_label = ba.Lstr(resource='backText') else: back_label = ba.Lstr(resource='doneText') self._width = 700.0 if ba.app.small_ui else 600.0 x_inset = 50.0 if ba.app.small_ui else 0.0 self._height = (360.0 if ba.app.small_ui else 385.0 if ba.app.med_ui else 410.0) # If we're being called up standalone, handle pause/resume ourself. if not self._in_main_menu: ba.app.pause() # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() transition = 'in_scale' else: self._transition_out = 'out_right' scale_origin = None self._r = 'playerProfilesWindow' # Ensure we've got an account-profile in cases where we're signed in. ensure_have_account_player_profile() top_extra = 20 if ba.app.small_ui else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, scale_origin_stack_offset=scale_origin, scale=(2.2 if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.0), stack_offset=(0, -14) if ba.app.small_ui else (0, 0))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(40 + x_inset, self._height - 59), size=(120, 60), scale=0.8, label=back_label, button_type='back' if self._in_main_menu else None, autoselect=True, on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 36), size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=300, color=ba.app.title_color, scale=0.9, h_align="center", v_align="center") if self._in_main_menu: ba.buttonwidget(edit=btn, button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) scroll_height = self._height - 140.0 self._scroll_width = self._width - (188 + x_inset * 2) v = self._height - 84.0 h = 50 + x_inset b_color = (0.6, 0.53, 0.63) scl = (1.055 if ba.app.small_ui else 1.18 if ba.app.med_ui else 1.3) v -= 70.0 * scl self._new_button = ba.buttonwidget(parent=self._root_widget, position=(h, v), size=(80, 66.0 * scl), on_activate_call=self._new_profile, color=b_color, button_type='square', autoselect=True, textcolor=(0.75, 0.7, 0.8), text_scale=0.7, label=ba.Lstr(resource=self._r + '.newButtonText')) v -= 70.0 * scl self._edit_button = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(80, 66.0 * scl), on_activate_call=self._edit_profile, color=b_color, button_type='square', autoselect=True, textcolor=(0.75, 0.7, 0.8), text_scale=0.7, label=ba.Lstr(resource=self._r + '.editButtonText')) v -= 70.0 * scl self._delete_button = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(80, 66.0 * scl), on_activate_call=self._delete_profile, color=b_color, button_type='square', autoselect=True, textcolor=(0.75, 0.7, 0.8), text_scale=0.7, label=ba.Lstr(resource=self._r + '.deleteButtonText')) v = self._height - 87 ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 71), size=(0, 0), text=ba.Lstr(resource=self._r + '.explanationText'), color=ba.app.infotextcolor, maxwidth=self._width * 0.83, scale=0.6, h_align="center", v_align="center") self._scrollwidget = ba.scrollwidget(parent=self._root_widget, highlight=False, position=(140 + x_inset, v - scroll_height), size=(self._scroll_width, scroll_height)) ba.widget(edit=self._scrollwidget, autoselect=True, left_widget=self._new_button) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) self._columnwidget = ba.columnwidget(parent=self._scrollwidget) v -= 255 self._profiles: Optional[Dict[str, Dict[str, Any]]] = None self._selected_profile = selected_profile self._profile_widgets: List[ba.Widget] = [] self._refresh() self._restore_state()