def __init__(self, editcontroller: PlaylistEditController, transition: str = 'in_right'): # pylint: disable=too-many-statements # pylint: disable=too-many-locals prev_selection: Optional[str] self._editcontroller = editcontroller self._r = 'editGameListWindow' prev_selection = self._editcontroller.get_edit_ui_selection() uiscale = ba.app.uiscale self._width = 770 if uiscale is ba.UIScale.SMALL else 670 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = (400 if uiscale is ba.UIScale.SMALL else 470 if uiscale is ba.UIScale.MEDIUM else 540) 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=(2.0 if uiscale is ba.UIScale.SMALL else 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -16) if uiscale is ba.UIScale.SMALL else (0, 0))) cancel_button = ba.buttonwidget(parent=self._root_widget, position=(35 + x_inset, self._height - 60), scale=0.8, size=(175, 60), autoselect=True, label=ba.Lstr(resource='cancelText'), text_scale=1.2) save_button = btn = ba.buttonwidget( parent=self._root_widget, position=(self._width - (195 + x_inset), self._height - 60), scale=0.8, size=(190, 60), autoselect=True, left_widget=cancel_button, label=ba.Lstr(resource='saveText'), text_scale=1.2) if ba.app.toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=cancel_button, left_widget=cancel_button, right_widget=save_button) ba.textwidget(parent=self._root_widget, position=(-10, self._height - 50), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.title_color, scale=1.05, h_align='center', v_align='center', maxwidth=270) v = self._height - 115.0 self._scroll_width = self._width - (205 + 2 * x_inset) ba.textwidget(parent=self._root_widget, text=ba.Lstr(resource=self._r + '.listNameText'), position=(196 + x_inset, v + 31), maxwidth=150, color=(0.8, 0.8, 0.8, 0.5), size=(0, 0), scale=0.75, h_align='right', v_align='center') self._text_field = ba.textwidget( parent=self._root_widget, position=(210 + x_inset, v + 7), size=(self._scroll_width - 53, 43), text=self._editcontroller.getname(), h_align='left', v_align='center', max_chars=40, autoselect=True, color=(0.9, 0.9, 0.9, 1.0), description=ba.Lstr(resource=self._r + '.listNameText'), editable=True, padding=4, on_return_press_call=self._save_press_with_sound) ba.widget(edit=cancel_button, down_widget=self._text_field) self._list_widgets: List[ba.Widget] = [] h = 40 + x_inset v = self._height - 172.0 b_color = (0.6, 0.53, 0.63) b_textcolor = (0.75, 0.7, 0.8) v -= 2.0 v += 63 scl = (1.03 if uiscale is ba.UIScale.SMALL else 1.36 if uiscale is ba.UIScale.MEDIUM else 1.74) v -= 63.0 * scl add_game_button = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(110, 61.0 * scl), on_activate_call=self._add, on_select_call=ba.Call(self._set_ui_selection, 'add_button'), autoselect=True, button_type='square', color=b_color, textcolor=b_textcolor, text_scale=0.8, label=ba.Lstr(resource=self._r + '.addGameText')) ba.widget(edit=add_game_button, up_widget=self._text_field) v -= 63.0 * scl self._edit_button = edit_game_button = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(110, 61.0 * scl), on_activate_call=self._edit, on_select_call=ba.Call(self._set_ui_selection, 'editButton'), autoselect=True, button_type='square', color=b_color, textcolor=b_textcolor, text_scale=0.8, label=ba.Lstr(resource=self._r + '.editGameText')) v -= 63.0 * scl remove_game_button = ba.buttonwidget(parent=self._root_widget, position=(h, v), size=(110, 61.0 * scl), text_scale=0.8, on_activate_call=self._remove, autoselect=True, button_type='square', color=b_color, textcolor=b_textcolor, label=ba.Lstr(resource=self._r + '.removeGameText')) v -= 40 h += 9 ba.buttonwidget(parent=self._root_widget, position=(h, v), size=(42, 35), on_activate_call=self._move_up, label=ba.charstr(ba.SpecialChar.UP_ARROW), button_type='square', color=b_color, textcolor=b_textcolor, autoselect=True, repeat=True) h += 52 ba.buttonwidget(parent=self._root_widget, position=(h, v), size=(42, 35), on_activate_call=self._move_down, autoselect=True, button_type='square', color=b_color, textcolor=b_textcolor, label=ba.charstr(ba.SpecialChar.DOWN_ARROW), repeat=True) v = self._height - 100 scroll_height = self._height - 155 scrollwidget = ba.scrollwidget( parent=self._root_widget, position=(160 + x_inset, v - scroll_height), highlight=False, on_select_call=ba.Call(self._set_ui_selection, 'gameList'), size=(self._scroll_width, (scroll_height - 15))) ba.widget(edit=scrollwidget, left_widget=add_game_button, right_widget=scrollwidget) self._columnwidget = ba.columnwidget(parent=scrollwidget) ba.widget(edit=self._columnwidget, up_widget=self._text_field) for button in [add_game_button, edit_game_button, remove_game_button]: ba.widget(edit=button, left_widget=button, right_widget=scrollwidget) self._refresh() ba.buttonwidget(edit=cancel_button, on_activate_call=self._cancel) ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button, selected_child=scrollwidget) ba.buttonwidget(edit=save_button, on_activate_call=self._save_press) ba.containerwidget(edit=self._root_widget, start_button=save_button) if prev_selection == 'add_button': ba.containerwidget(edit=self._root_widget, selected_child=add_game_button) elif prev_selection == 'editButton': ba.containerwidget(edit=self._root_widget, selected_child=edit_game_button) elif prev_selection == 'gameList': ba.containerwidget(edit=self._root_widget, selected_child=scrollwidget)
def ask_for_rating() -> Optional[ba.Widget]: """(internal)""" app = ba.app platform = app.platform subplatform = app.subplatform if not (platform == 'mac' or (platform == 'android' and subplatform in ['google', 'cardboard'])): return None width = 700 height = 400 spacing = 40 dlg = ba.containerwidget( size=(width, height), transition='in_right', scale=1.6 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0) v = height - 50 v -= spacing v -= 140 ba.imagewidget(parent=dlg, position=(width / 2 - 100, v + 10), size=(200, 200), texture=ba.gettexture('cuteSpaz')) ba.textwidget(parent=dlg, position=(15, v - 55), size=(width - 30, 30), color=ba.app.infotextcolor, text=ba.Lstr(resource='pleaseRateText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), maxwidth=width * 0.95, max_height=130, scale=0.85, h_align='center', v_align='center') def do_rating() -> None: if platform == 'android': if subplatform == 'google': url = 'market://details?id=net.froemling.ballisticacore' else: url = 'market://details?id=net.froemling.ballisticacorecb' else: url = 'macappstore://itunes.apple.com/app/id416482767?ls=1&mt=12' ba.open_url(url) ba.containerwidget(edit=dlg, transition='out_left') ba.buttonwidget(parent=dlg, position=(60, 20), size=(200, 60), label=ba.Lstr(resource='wellSureText'), autoselect=True, on_activate_call=do_rating) def close() -> None: ba.containerwidget(edit=dlg, transition='out_left') btn = ba.buttonwidget(parent=dlg, position=(width - 270, 20), size=(200, 60), label=ba.Lstr(resource='noThanksText'), autoselect=True, on_activate_call=close) ba.containerwidget(edit=dlg, cancel_button=btn, selected_child=btn) return dlg
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 interface_type = app.interface_type width = 450.0 height = 302.0 self._show_fullscreen = False fullscreen_spacing_top = spacing * 0.2 fullscreen_spacing = spacing * 1.2 if interface_type == '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') base_scale = (2.4 if ba.app.small_ui else 1.5 if ba.app.med_ui 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 ba.app.small_ui 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.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.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.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.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.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.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.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 _update(self) -> None: # pylint: disable=too-many-boolean-expressions from ba.internal import getcampaign # In case we stick around after our UI... if not self._button: return game = self._game campaignname, levelname = game.split(':') # Hack - The Last Stand doesn't actually exist in the # easy tourney; we just want it for display purposes. Map it to # the hard-mode version. if game == 'Easy:The Last Stand': campaignname = 'Default' campaign = getcampaign(campaignname) # If this campaign is sequential, make sure we've unlocked # everything up to here. unlocked = True if campaign.sequential: for level in campaign.levels: if level.name == levelname: break if not level.complete: unlocked = False break # We never actually allow playing last-stand on easy mode. if game == 'Easy:The Last Stand': unlocked = False # Hard-code games we haven't unlocked. if ((game in ('Challenges:Infinite Runaround', 'Challenges:Infinite Onslaught') and not ba.app.accounts_v1.have_pro()) or (game in ('Challenges:Meteor Shower', ) and not _ba.get_purchased('games.meteor_shower')) or (game in ('Challenges:Target Practice', 'Challenges:Target Practice B') and not _ba.get_purchased('games.target_practice')) or (game in ('Challenges:Ninja Fight', ) and not _ba.get_purchased('games.ninja_fight')) or (game in ('Challenges:Pro Ninja Fight', ) and not _ba.get_purchased('games.ninja_fight')) or (game in ('Challenges:Easter Egg Hunt', 'Challenges:Pro Easter Egg Hunt') and not _ba.get_purchased('games.easter_egg_hunt'))): unlocked = False # Let's tint levels a slightly different color when easy mode # is selected. unlocked_color = (0.85, 0.95, 0.5) if game.startswith('Easy:') else (0.5, 0.7, 0.2) ba.buttonwidget(edit=self._button, color=unlocked_color if unlocked else (0.5, 0.5, 0.5)) ba.imagewidget(edit=self._lock_widget, opacity=0.0 if unlocked else 1.0) ba.imagewidget(edit=self._preview_widget, opacity=1.0 if unlocked else 0.3) ba.textwidget(edit=self._name_widget, color=(0.8, 1.0, 0.8, 1.0) if unlocked else (0.7, 0.7, 0.7, 0.7)) for widget in self._star_widgets: ba.imagewidget(edit=widget, opacity=1.0 if unlocked else 0.3, color=(2.2, 1.2, 0.3) if unlocked else (1, 1, 1)) for i, ach in enumerate(self._achievements): a_complete = ach.complete ba.imagewidget(edit=self._achievement_widgets[i][0], opacity=1.0 if (a_complete and unlocked) else 0.3) ba.imagewidget(edit=self._achievement_widgets[i][1], opacity=(1.0 if (a_complete and unlocked) else 0.2 if a_complete else 0.0))
def __init__(self, sessiontype: Type[ba.Session], playlist: str, scale_origin: Tuple[float, float], delegate: Any = None): # FIXME: Tidy this up. # pylint: disable=too-many-branches # pylint: disable=too-many-statements # pylint: disable=too-many-locals from ba.internal import (getclass, have_pro, get_default_teams_playlist, get_default_free_for_all_playlist, filter_playlist) from ba.internal import get_map_class from bastd.ui.playlist import PlaylistTypeVars self._r = 'gameListWindow' self._delegate = delegate self._pvars = PlaylistTypeVars(sessiontype) self._transitioning_out = False self._do_randomize_val = (ba.app.config.get( self._pvars.config_name + ' Playlist Randomize', 0)) self._sessiontype = sessiontype self._playlist = playlist self._width = 500.0 self._height = 330.0 - 50.0 # In teams games, show the custom names/colors button. if self._sessiontype is ba.DualTeamSession: self._height += 50.0 self._row_height = 45.0 # Grab our maps to display. model_opaque = ba.getmodel('level_select_button_opaque') model_transparent = ba.getmodel('level_select_button_transparent') mask_tex = ba.gettexture('mapPreviewMask') # Poke into this playlist and see if we can display some of its maps. map_textures = [] map_texture_entries = [] rows = 0 columns = 0 game_count = 0 scl = 0.35 c_width_total = 0.0 try: max_columns = 5 name = playlist if name == '__default__': if self._sessiontype is ba.FreeForAllSession: plst = get_default_free_for_all_playlist() elif self._sessiontype is ba.DualTeamSession: plst = get_default_teams_playlist() else: raise TypeError('unrecognized session-type: ' + str(self._sessiontype)) else: try: plst = ba.app.config[self._pvars.config_name + ' Playlists'][name] except Exception: print('ERROR INFO: self._config_name is:', self._pvars.config_name) print( 'ERROR INFO: playlist names are:', list(ba.app.config[self._pvars.config_name + ' Playlists'].keys())) raise plst = filter_playlist(plst, self._sessiontype, remove_unowned=False, mark_unowned=True) game_count = len(plst) for entry in plst: mapname = entry['settings']['map'] maptype: Optional[Type[ba.Map]] try: maptype = get_map_class(mapname) except ba.NotFoundError: maptype = None if maptype is not None: tex_name = maptype.get_preview_texture_name() if tex_name is not None: map_textures.append(tex_name) map_texture_entries.append(entry) rows = (max(0, len(map_textures) - 1) // max_columns) + 1 columns = min(max_columns, len(map_textures)) if len(map_textures) == 1: scl = 1.1 elif len(map_textures) == 2: scl = 0.7 elif len(map_textures) == 3: scl = 0.55 else: scl = 0.35 self._row_height = 128.0 * scl c_width_total = scl * 250.0 * columns if map_textures: self._height += self._row_height * rows except Exception: ba.print_exception('Error listing playlist maps.') show_shuffle_check_box = game_count > 1 if show_shuffle_check_box: self._height += 40 # Creates our _root_widget. uiscale = ba.app.ui.uiscale scale = (1.69 if uiscale is ba.UIScale.SMALL else 1.1 if uiscale is ba.UIScale.MEDIUM else 0.85) super().__init__(position=scale_origin, size=(self._width, self._height), scale=scale) playlist_name: Union[str, ba.Lstr] = (self._pvars.default_list_name if playlist == '__default__' else playlist) self._title_text = ba.textwidget(parent=self.root_widget, position=(self._width * 0.5, self._height - 89 + 51), size=(0, 0), text=playlist_name, scale=1.4, color=(1, 1, 1), maxwidth=self._width * 0.7, h_align='center', v_align='center') self._cancel_button = ba.buttonwidget( parent=self.root_widget, position=(25, self._height - 53), size=(50, 50), scale=0.7, label='', color=(0.42, 0.73, 0.2), on_activate_call=self._on_cancel_press, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) h_offs_img = self._width * 0.5 - c_width_total * 0.5 v_offs_img = self._height - 118 - scl * 125.0 + 50 bottom_row_buttons = [] self._have_at_least_one_owned = False for row in range(rows): for col in range(columns): tex_index = row * columns + col if tex_index < len(map_textures): tex_name = map_textures[tex_index] h = h_offs_img + scl * 250 * col v = v_offs_img - self._row_height * row entry = map_texture_entries[tex_index] owned = not (('is_unowned_map' in entry and entry['is_unowned_map']) or ('is_unowned_game' in entry and entry['is_unowned_game'])) if owned: self._have_at_least_one_owned = True try: desc = getclass(entry['type'], subclassof=ba.GameActivity ).get_settings_display_string(entry) if not owned: desc = ba.Lstr( value='${DESC}\n${UNLOCK}', subs=[ ('${DESC}', desc), ('${UNLOCK}', ba.Lstr( resource='unlockThisInTheStoreText')) ]) desc_color = (0, 1, 0) if owned else (1, 0, 0) except Exception: desc = ba.Lstr(value='(invalid)') desc_color = (1, 0, 0) btn = ba.buttonwidget( parent=self.root_widget, size=(scl * 240.0, scl * 120.0), position=(h, v), texture=ba.gettexture(tex_name if owned else 'empty'), model_opaque=model_opaque if owned else None, on_activate_call=ba.Call(ba.screenmessage, desc, desc_color), label='', color=(1, 1, 1), autoselect=True, extra_touch_border_scale=0.0, model_transparent=model_transparent if owned else None, mask_texture=mask_tex if owned else None) if row == 0 and col == 0: ba.widget(edit=self._cancel_button, down_widget=btn) if row == rows - 1: bottom_row_buttons.append(btn) if not owned: # Ewww; buttons don't currently have alpha so in this # case we draw an image over our button with an empty # texture on it. ba.imagewidget(parent=self.root_widget, size=(scl * 260.0, scl * 130.0), position=(h - 10.0 * scl, v - 4.0 * scl), draw_controller=btn, color=(1, 1, 1), texture=ba.gettexture(tex_name), model_opaque=model_opaque, opacity=0.25, model_transparent=model_transparent, mask_texture=mask_tex) ba.imagewidget(parent=self.root_widget, size=(scl * 100, scl * 100), draw_controller=btn, position=(h + scl * 70, v + scl * 10), texture=ba.gettexture('lock')) # Team names/colors. self._custom_colors_names_button: Optional[ba.Widget] if self._sessiontype is ba.DualTeamSession: y_offs = 50 if show_shuffle_check_box else 0 self._custom_colors_names_button = ba.buttonwidget( parent=self.root_widget, position=(100, 200 + y_offs), size=(290, 35), on_activate_call=ba.WeakCall(self._custom_colors_names_press), autoselect=True, textcolor=(0.8, 0.8, 0.8), label=ba.Lstr(resource='teamNamesColorText')) if not have_pro(): ba.imagewidget( parent=self.root_widget, size=(30, 30), position=(95, 202 + y_offs), texture=ba.gettexture('lock'), draw_controller=self._custom_colors_names_button) else: self._custom_colors_names_button = None # Shuffle. def _cb_callback(val: bool) -> None: self._do_randomize_val = val cfg = ba.app.config cfg[self._pvars.config_name + ' Playlist Randomize'] = self._do_randomize_val cfg.commit() if show_shuffle_check_box: self._shuffle_check_box = ba.checkboxwidget( parent=self.root_widget, position=(110, 200), scale=1.0, size=(250, 30), autoselect=True, text=ba.Lstr(resource=self._r + '.shuffleGameOrderText'), maxwidth=300, textcolor=(0.8, 0.8, 0.8), value=self._do_randomize_val, on_value_change_call=_cb_callback) # Show tutorial. show_tutorial = bool(ba.app.config.get('Show Tutorial', True)) def _cb_callback_2(val: bool) -> None: cfg = ba.app.config cfg['Show Tutorial'] = val cfg.commit() self._show_tutorial_check_box = ba.checkboxwidget( parent=self.root_widget, position=(110, 151), scale=1.0, size=(250, 30), autoselect=True, text=ba.Lstr(resource=self._r + '.showTutorialText'), maxwidth=300, textcolor=(0.8, 0.8, 0.8), value=show_tutorial, on_value_change_call=_cb_callback_2) # Grumble: current autoselect doesn't do a very good job # with checkboxes. if self._custom_colors_names_button is not None: for btn in bottom_row_buttons: ba.widget(edit=btn, down_widget=self._custom_colors_names_button) if show_shuffle_check_box: ba.widget(edit=self._custom_colors_names_button, down_widget=self._shuffle_check_box) ba.widget(edit=self._shuffle_check_box, up_widget=self._custom_colors_names_button) else: ba.widget(edit=self._custom_colors_names_button, down_widget=self._show_tutorial_check_box) ba.widget(edit=self._show_tutorial_check_box, up_widget=self._custom_colors_names_button) self._play_button = ba.buttonwidget( parent=self.root_widget, position=(70, 44), size=(200, 45), scale=1.8, text_res_scale=1.5, on_activate_call=self._on_play_press, autoselect=True, label=ba.Lstr(resource='playText')) ba.widget(edit=self._play_button, up_widget=self._show_tutorial_check_box) ba.containerwidget(edit=self.root_widget, start_button=self._play_button, cancel_button=self._cancel_button, selected_child=self._play_button) # Update now and once per second. self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) self._update()
def _refresh_in_game( self, positions: List[Tuple[float, float, float]]) -> Tuple[float, float, float]: # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements custom_menu_entries: List[Dict[str, Any]] = [] session = _ba.get_foreground_host_session() if session is not None: try: custom_menu_entries = session.get_custom_menu_entries() for cme in custom_menu_entries: if (not isinstance(cme, dict) or 'label' not in cme or not isinstance(cme['label'], (str, ba.Lstr)) or 'call' not in cme or not callable(cme['call'])): raise Exception('invalid custom menu entry: ' + str(cme)) except Exception: custom_menu_entries = [] ba.print_exception('exception getting custom menu entries for', session) self._width = 250.0 self._height = 250.0 if self._input_player else 180.0 if self._is_kiosk and self._input_player: self._height -= 40 if not self._have_settings_button: self._height -= 50 if self._connected_to_remote_player: # In this case we have a leave *and* a disconnect button. self._height += 50 self._height += 50 * (len(custom_menu_entries)) ba.containerwidget( edit=self._root_widget, size=(self._width, self._height), scale=2.15 if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.0) h = 125.0 v = (self._height - 80.0 if self._input_player else self._height - 60) h_offset = 0 d_h_offset = 0 v_offset = -50 for _i in range(6 + len(custom_menu_entries)): positions.append((h, v, 1.0)) v += v_offset h += h_offset h_offset += d_h_offset self._start_button = None ba.app.pause() # Player name if applicable. if self._input_player: player_name = self._input_player.get_name() h, v, scale = positions[self._p_index] v += 35 ba.textwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), color=(1, 1, 1, 0.5), scale=0.7, h_align='center', text=ba.Lstr(value=player_name)) else: player_name = '' h, v, scale = positions[self._p_index] self._p_index += 1 btn = ba.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), scale=scale, label=ba.Lstr(resource=self._r + '.resumeText'), autoselect=self._use_autoselect, on_activate_call=self._resume) ba.containerwidget(edit=self._root_widget, cancel_button=btn) # Add any custom options defined by the current game. for entry in custom_menu_entries: h, v, scale = positions[self._p_index] self._p_index += 1 # Ask the entry whether we should resume when we call # it (defaults to true). try: resume = entry['resume_on_call'] except Exception: resume = True if resume: call = ba.Call(self._resume_and_call, entry['call']) else: call = ba.Call(entry['call'], ba.WeakCall(self._resume)) ba.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), scale=scale, on_activate_call=call, label=entry['label'], autoselect=self._use_autoselect) # Add a 'leave' button if the menu-owner has a player. if ((self._input_player or self._connected_to_remote_player) and not self._is_kiosk): h, v, scale = positions[self._p_index] self._p_index += 1 btn = ba.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), scale=scale, on_activate_call=self._leave, label='', autoselect=self._use_autoselect) if (player_name != '' and player_name[0] != '<' and player_name[-1] != '>'): txt = ba.Lstr(resource=self._r + '.justPlayerText', subs=[('${NAME}', player_name)]) else: txt = ba.Lstr(value=player_name) ba.textwidget(parent=self._root_widget, position=(h, v + self._button_height * (0.64 if player_name != '' else 0.5)), size=(0, 0), text=ba.Lstr(resource=self._r + '.leaveGameText'), scale=(0.83 if player_name != '' else 1.0), color=(0.75, 1.0, 0.7), h_align='center', v_align='center', draw_controller=btn, maxwidth=self._button_width * 0.9) ba.textwidget(parent=self._root_widget, position=(h, v + self._button_height * 0.27), size=(0, 0), text=txt, color=(0.75, 1.0, 0.7), h_align='center', v_align='center', draw_controller=btn, scale=0.45, maxwidth=self._button_width * 0.9) return h, v, scale
def _refresh(self) -> None: from ba.deprecated import get_resource for widget in self._col.get_children(): widget.delete() types = [ 'Menu', 'CharSelect', 'ToTheDeath', 'Onslaught', 'Keep Away', 'Race', 'Epic Race', 'ForwardMarch', 'FlagCatcher', 'Survival', 'Epic', 'Hockey', 'Football', 'Flying', 'Scary', 'Marching', 'GrandRomp', 'Chosen One', 'Scores', 'Victory', ] # FIXME: We should probably convert this to use translations. type_names_translated = get_resource('soundtrackTypeNames') prev_type_button: Optional[ba.Widget] = None prev_test_button: Optional[ba.Widget] = None for index, song_type in enumerate(types): row = ba.rowwidget(parent=self._col, size=(self._width - 40, 40)) ba.containerwidget(edit=row, claims_left_right=True, claims_tab=True, selection_loop_to_parent=True) try: type_name = type_names_translated[song_type] except Exception: type_name = song_type ba.textwidget(parent=row, size=(230, 25), always_highlight=True, text=type_name, scale=0.7, h_align='left', v_align='center', maxwidth=190) if song_type in self._soundtrack: entry = self._soundtrack[song_type] else: entry = None if entry is not None: # make sure they don't muck with this after it gets to us entry = copy.deepcopy(entry) icon_type = self._get_entry_button_display_icon_type(entry) self._song_type_buttons[song_type] = btn = ba.buttonwidget( parent=row, size=(230, 32), label=self._get_entry_button_display_name(entry), text_scale=0.6, on_activate_call=ba.Call(self._get_entry, song_type, entry, type_name), icon=(self._file_tex if icon_type == 'file' else self._folder_tex if icon_type == 'folder' else None), icon_color=(1.1, 0.8, 0.2) if icon_type == 'folder' else (1, 1, 1), left_widget=self._text_field, iconscale=0.7, autoselect=True, up_widget=prev_type_button) if index == 0: ba.widget(edit=btn, up_widget=self._text_field) ba.widget(edit=btn, down_widget=btn) if (self._last_edited_song_type is not None and song_type == self._last_edited_song_type): ba.containerwidget(edit=row, selected_child=btn, visible_child=btn) ba.containerwidget(edit=self._col, selected_child=row, visible_child=row) ba.containerwidget(edit=self._scrollwidget, selected_child=self._col, visible_child=self._col) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget, visible_child=self._scrollwidget) if prev_type_button is not None: ba.widget(edit=prev_type_button, down_widget=btn) prev_type_button = btn ba.textwidget(parent=row, size=(10, 32), text='') # spacing # (looks like a PyCharm false positive) # noinspection PyArgumentList btn = ba.buttonwidget( parent=row, size=(50, 32), label=ba.Lstr(resource=self._r + '.testText'), text_scale=0.6, on_activate_call=ba.Call(self._test, ba.MusicType(song_type)), up_widget=prev_test_button if prev_test_button is not None else self._text_field) if prev_test_button is not None: ba.widget(edit=prev_test_button, down_widget=btn) ba.widget(edit=btn, down_widget=btn, right_widget=btn) prev_test_button = btn
def __init__(self, existing_profile: Optional[str], in_main_menu: bool, transition: str = 'in_right'): # FIXME: Tidy this up a bit. # pylint: disable=too-many-branches # pylint: disable=too-many-statements # pylint: disable=too-many-locals from ba.internal import get_player_profile_colors self._in_main_menu = in_main_menu self._existing_profile = existing_profile self._r = 'editProfileWindow' self._spazzes: List[str] = [] self._icon_textures: List[ba.Texture] = [] self._icon_tint_textures: List[ba.Texture] = [] # Grab profile colors or pick random ones. self._color, self._highlight = get_player_profile_colors( existing_profile) self._width = width = 780.0 if ba.app.small_ui else 680.0 self._x_inset = x_inset = 50.0 if ba.app.small_ui else 0.0 self._height = height = (350.0 if ba.app.small_ui else 400.0 if ba.app.med_ui else 450.0) spacing = 40 self._base_scale = (2.05 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0) top_extra = 15 if ba.app.small_ui else 15 super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, scale=self._base_scale, stack_offset=(0, 15) if ba.app.small_ui else (0, 0))) cancel_button = btn = ba.buttonwidget( parent=self._root_widget, position=(52 + x_inset, height - 60), size=(155, 60), scale=0.8, autoselect=True, label=ba.Lstr(resource='cancelText'), on_activate_call=self._cancel) ba.containerwidget(edit=self._root_widget, cancel_button=btn) save_button = btn = ba.buttonwidget(parent=self._root_widget, position=(width - (177 + x_inset), height - 60), size=(155, 60), autoselect=True, scale=0.8, label=ba.Lstr(resource='saveText')) ba.widget(edit=save_button, left_widget=cancel_button) ba.widget(edit=cancel_button, right_widget=save_button) ba.containerwidget(edit=self._root_widget, start_button=btn) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, height - 38), size=(0, 0), text=(ba.Lstr(resource=self._r + '.titleNewText') if existing_profile is None else ba.Lstr( resource=self._r + '.titleEditText')), color=ba.app.title_color, maxwidth=290, scale=1.0, h_align='center', v_align='center') # Make a list of spaz icons. self.refresh_characters() profile = ba.app.config.get('Player Profiles', {}).get(self._existing_profile, {}) if 'global' in profile: self._global = profile['global'] else: self._global = False if 'icon' in profile: self._icon = profile['icon'] else: self._icon = ba.charstr(ba.SpecialChar.LOGO) assigned_random_char = False # Look for existing character choice or pick random one otherwise. try: icon_index = self._spazzes.index(profile['character']) except Exception: # Let's set the default icon to spaz for our first profile; after # that we go random. # (SCRATCH THAT.. we now hard-code account-profiles to start with # spaz which has a similar effect) # try: p_len = len(ba.app.config['Player Profiles']) # except Exception: p_len = 0 # if p_len == 0: icon_index = self._spazzes.index('Spaz') # else: random.seed() icon_index = random.randrange(len(self._spazzes)) assigned_random_char = True self._icon_index = icon_index ba.buttonwidget(edit=save_button, on_activate_call=self.save) v = height - 115.0 self._name = ('' if self._existing_profile is None else self._existing_profile) self._is_account_profile = (self._name == '__account__') # If we just picked a random character, see if it has specific # colors/highlights associated with it and assign them if so. if assigned_random_char: clr = ba.app.spaz_appearances[ self._spazzes[icon_index]].default_color if clr is not None: self._color = clr highlight = ba.app.spaz_appearances[ self._spazzes[icon_index]].default_highlight if highlight is not None: self._highlight = highlight # Assign a random name if they had none. if self._name == '': names = _ba.get_random_names() self._name = names[random.randrange(len(names))] self._clipped_name_text = ba.textwidget(parent=self._root_widget, text='', position=(540 + x_inset, v - 8), flatness=1.0, shadow=0.0, scale=0.55, size=(0, 0), maxwidth=100, h_align='center', v_align='center', color=(1, 1, 0, 0.5)) if not self._is_account_profile and not self._global: ba.textwidget(parent=self._root_widget, text=ba.Lstr(resource=self._r + '.nameText'), position=(200 + x_inset, v - 6), size=(0, 0), h_align='right', v_align='center', color=(1, 1, 1, 0.5), scale=0.9) self._upgrade_button = None if self._is_account_profile: if _ba.get_account_state() == 'signed_in': sval = _ba.get_account_display_string() else: sval = '??' ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, v - 7), size=(0, 0), scale=1.2, text=sval, maxwidth=270, h_align='center', v_align='center') txtl = ba.Lstr( resource='editProfileWindow.accountProfileText').evaluate() b_width = min( 270.0, _ba.get_string_width(txtl, suppress_warning=True) * 0.6) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, v - 39), size=(0, 0), scale=0.6, color=ba.app.infotextcolor, text=txtl, maxwidth=270, h_align='center', v_align='center') self._account_type_info_button = ba.buttonwidget( parent=self._root_widget, label='?', size=(15, 15), text_scale=0.6, position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), button_type='square', color=(0.6, 0.5, 0.65), autoselect=True, on_activate_call=self.show_account_profile_info) elif self._global: b_size = 60 self._icon_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.5 - 160 - b_size * 0.5, v - 38 - 15), size=(b_size, b_size), color=(0.6, 0.5, 0.6), label='', button_type='square', text_scale=1.2, on_activate_call=self._on_icon_press) self._icon_button_label = ba.textwidget( parent=self._root_widget, position=(self._width * 0.5 - 160, v - 35), draw_controller=btn, h_align='center', v_align='center', size=(0, 0), color=(1, 1, 1), text='', scale=2.0) ba.textwidget(parent=self._root_widget, h_align='center', v_align='center', position=(self._width * 0.5 - 160, v - 55 - 15), size=(0, 0), draw_controller=btn, text=ba.Lstr(resource=self._r + '.iconText'), scale=0.7, color=ba.app.title_color, maxwidth=120) self._update_icon() ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, v - 7), size=(0, 0), scale=1.2, text=self._name, maxwidth=240, h_align='center', v_align='center') # FIXME hard coded strings are bad txtl = ba.Lstr( resource='editProfileWindow.globalProfileText').evaluate() b_width = min( 240.0, _ba.get_string_width(txtl, suppress_warning=True) * 0.6) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, v - 39), size=(0, 0), scale=0.6, color=ba.app.infotextcolor, text=txtl, maxwidth=240, h_align='center', v_align='center') self._account_type_info_button = ba.buttonwidget( parent=self._root_widget, label='?', size=(15, 15), text_scale=0.6, position=(self._width * 0.5 + b_width * 0.5 + 13, v - 47), button_type='square', color=(0.6, 0.5, 0.65), autoselect=True, on_activate_call=self.show_global_profile_info) else: self._text_field = ba.textwidget( parent=self._root_widget, position=(220 + x_inset, v - 30), size=(265, 40), text=self._name, h_align='left', v_align='center', max_chars=16, description=ba.Lstr(resource=self._r + '.nameDescriptionText'), autoselect=True, editable=True, padding=4, color=(0.9, 0.9, 0.9, 1.0), on_return_press_call=ba.Call(save_button.activate)) # FIXME hard coded strings are bad txtl = ba.Lstr( resource='editProfileWindow.localProfileText').evaluate() b_width = min( 270.0, _ba.get_string_width(txtl, suppress_warning=True) * 0.6) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, v - 43), size=(0, 0), scale=0.6, color=ba.app.infotextcolor, text=txtl, maxwidth=270, h_align='center', v_align='center') self._account_type_info_button = ba.buttonwidget( parent=self._root_widget, label='?', size=(15, 15), text_scale=0.6, position=(self._width * 0.5 + b_width * 0.5 + 13, v - 50), button_type='square', color=(0.6, 0.5, 0.65), autoselect=True, on_activate_call=self.show_local_profile_info) self._upgrade_button = ba.buttonwidget( parent=self._root_widget, label=ba.Lstr(resource='upgradeText'), size=(40, 17), text_scale=1.0, button_type='square', position=(self._width * 0.5 + b_width * 0.5 + 13 + 43, v - 51), color=(0.6, 0.5, 0.65), autoselect=True, on_activate_call=self.upgrade_profile) self._update_clipped_name() self._clipped_name_timer = ba.Timer(0.333, ba.WeakCall( self._update_clipped_name), timetype=ba.TimeType.REAL, repeat=True) v -= spacing * 3.0 b_size = 80 b_size_2 = 100 b_offs = 150 self._color_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50), size=(b_size, b_size), color=self._color, label='', button_type='square') origin = self._color_button.get_screen_space_center() ba.buttonwidget(edit=self._color_button, on_activate_call=ba.WeakCall(self._make_picker, 'color', origin)) ba.textwidget(parent=self._root_widget, h_align='center', v_align='center', position=(self._width * 0.5 - b_offs, v - 65), size=(0, 0), draw_controller=btn, text=ba.Lstr(resource=self._r + '.colorText'), scale=0.7, color=ba.app.title_color, maxwidth=120) self._character_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.5 - b_size_2 * 0.5, v - 60), up_widget=self._account_type_info_button, on_activate_call=self._on_character_press, size=(b_size_2, b_size_2), label='', color=(1, 1, 1), mask_texture=ba.gettexture('characterIconMask')) if not self._is_account_profile and not self._global: ba.containerwidget(edit=self._root_widget, selected_child=self._text_field) ba.textwidget(parent=self._root_widget, h_align='center', v_align='center', position=(self._width * 0.5, v - 80), size=(0, 0), draw_controller=btn, text=ba.Lstr(resource=self._r + '.characterText'), scale=0.7, color=ba.app.title_color, maxwidth=130) self._highlight_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), up_widget=self._upgrade_button if self._upgrade_button is not None else self._account_type_info_button, size=(b_size, b_size), color=self._highlight, label='', button_type='square') if not self._is_account_profile and not self._global: ba.widget(edit=cancel_button, down_widget=self._text_field) ba.widget(edit=save_button, down_widget=self._text_field) ba.widget(edit=self._color_button, up_widget=self._text_field) ba.widget(edit=self._account_type_info_button, down_widget=self._character_button) origin = self._highlight_button.get_screen_space_center() ba.buttonwidget(edit=self._highlight_button, on_activate_call=ba.WeakCall(self._make_picker, 'highlight', origin)) ba.textwidget(parent=self._root_widget, h_align='center', v_align='center', position=(self._width * 0.5 + b_offs, v - 65), size=(0, 0), draw_controller=btn, text=ba.Lstr(resource=self._r + '.highlightText'), scale=0.7, color=ba.app.title_color, maxwidth=120) self._update_character()
def _set_color(self, color: Tuple[float, float, float]) -> None: self._color = color if self._color_button: ba.buttonwidget(edit=self._color_button, color=color)
def __init__(self, data: Dict[str, Any]): from ba.internal import is_browser_likely_available ba.set_analytics_screen('Friend Promo Code') self._width = 650 self._height = 400 uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), transition='in_scale', scale=(1.7 if uiscale is ba.UIScale.SMALL else 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._data = copy.deepcopy(data) ba.playsound(ba.getsound('cashRegister')) ba.playsound(ba.getsound('swish')) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=0.7, position=(50, self._height - 50), size=(60, 60), label='', on_activate_call=self.close, autoselect=True, color=(0.45, 0.63, 0.15), 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.8), size=(0, 0), color=ba.app.infotextcolor, scale=1.0, flatness=1.0, h_align='center', v_align='center', text=ba.Lstr(resource='gatherWindow.shareThisCodeWithFriendsText'), maxwidth=self._width * 0.85) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height * 0.645), size=(0, 0), color=(1.0, 3.0, 1.0), scale=2.0, h_align='center', v_align='center', text=data['code'], maxwidth=self._width * 0.85) award_str: Optional[Union[str, ba.Lstr]] if self._data['awardTickets'] != 0: award_str = ba.Lstr( resource='gatherWindow.friendPromoCodeAwardText', subs=[('${COUNT}', str(self._data['awardTickets']))]) else: award_str = '' ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.37), size=(0, 0), color=ba.app.infotextcolor, scale=1.0, flatness=1.0, h_align='center', v_align='center', text=ba.Lstr( value='${A}\n${B}\n${C}\n${D}', subs=[ ('${A}', ba.Lstr( resource='gatherWindow.friendPromoCodeRedeemLongText', subs=[('${COUNT}', str(self._data['tickets'])), ('${MAX_USES}', str(self._data['usesRemaining']))])), ('${B}', ba.Lstr(resource=( 'gatherWindow.friendPromoCodeWhereToEnterText'))), ('${C}', award_str), ('${D}', ba.Lstr(resource='gatherWindow.friendPromoCodeExpireText', subs=[('${EXPIRE_HOURS}', str(self._data['expireHours']))])) ]), maxwidth=self._width * 0.9, max_height=self._height * 0.35) if is_browser_likely_available(): xoffs = 0 ba.buttonwidget(parent=self._root_widget, size=(200, 40), position=(self._width * 0.5 - 100 + xoffs, 39), autoselect=True, label=ba.Lstr(resource='gatherWindow.emailItText'), on_activate_call=ba.WeakCall(self._email))
def __init__(self) -> None: ba.set_analytics_screen('AppInviteWindow') self._data: Optional[Dict[str, Any]] = None self._width = 650 self._height = 400 uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', 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.8, position=(60, self._height - 50), size=(50, 50), label='', on_activate_call=self.close, autoselect=True, color=(0.4, 0.4, 0.6), icon=ba.gettexture('crossOut'), iconscale=1.2) ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) ba.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height * 0.5 + 110), autoselect=True, scale=0.8, maxwidth=self._width * 0.9, h_align='center', v_align='center', color=(0.3, 0.8, 0.3), flatness=1.0, text=ba.Lstr( resource='gatherWindow.earnTicketsForRecommendingAmountText', fallback_resource=( 'gatherWindow.earnTicketsForRecommendingText'), subs=[ ('${COUNT}', str(_ba.get_account_misc_read_val('friendTryTickets', 300))), ('${YOU_COUNT}', str( _ba.get_account_misc_read_val('friendTryAwardTickets', 100))) ])) or_text = ba.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')]).evaluate().strip() ba.buttonwidget( parent=self._root_widget, size=(250, 150), position=(self._width * 0.5 - 125, self._height * 0.5 - 80), autoselect=True, button_type='square', label=ba.Lstr(resource='gatherWindow.inviteFriendsText'), on_activate_call=ba.WeakCall(self._google_invites)) ba.textwidget(parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height * 0.5 - 94), autoselect=True, scale=0.9, h_align='center', v_align='center', color=(0.5, 0.5, 0.5), flatness=1.0, text=or_text) ba.buttonwidget( parent=self._root_widget, size=(180, 50), position=(self._width * 0.5 - 90, self._height * 0.5 - 170), autoselect=True, color=(0.5, 0.5, 0.6), textcolor=(0.7, 0.7, 0.8), text_scale=0.8, label=ba.Lstr(resource='gatherWindow.appInviteSendACodeText'), on_activate_call=ba.WeakCall(self._send_code)) # kick off a transaction to get our code _ba.add_transaction( { 'type': 'FRIEND_PROMO_CODE_REQUEST', 'ali': False, 'expire_time': time.time() + 20 }, callback=ba.WeakCall(self._on_code_result)) _ba.run_transactions()
def __init__(self, transition: str = 'in_right'): # pylint: disable=too-many-locals, too-many-statements from bastd.ui import confirm self._width = 720.0 self._height = 340.0 def _do_cancel() -> None: confirm.QuitWindow(swish=True, back=True) super().__init__( root_widget=ba.containerwidget(size=(self._width, self._height), transition=transition, on_cancel_call=_do_cancel, background=False, stack_offset=(0, -130))) self._r = 'kioskWindow' self._show_multiplayer = False # Let's reset all random player names every time we hit the main menu. _ba.reset_random_player_names() # Reset achievements too (at least locally). ba.app.config['Achievements'] = {} t_delay_base = 0.0 t_delay_scale = 0.0 if not ba.app.did_menu_intro: t_delay_base = 1.0 t_delay_scale = 1.0 model_opaque = ba.getmodel('level_select_button_opaque') model_transparent = ba.getmodel('level_select_button_transparent') mask_tex = ba.gettexture('mapPreviewMask') y_extra = 130.0 + (0.0 if self._show_multiplayer else -130.0) b_width = 250.0 b_height = 200.0 b_space = 280.0 b_v = 80.0 + y_extra label_height = 130.0 + y_extra img_width = 180.0 img_v = 158.0 + y_extra if self._show_multiplayer: tdelay = t_delay_base + t_delay_scale * 1.3 ba.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 44), transition_delay=tdelay, text=ba.Lstr(resource=self._r + '.singlePlayerExamplesText'), flatness=1.0, scale=1.2, h_align='center', v_align='center', shadow=1.0) else: tdelay = t_delay_base + t_delay_scale * 0.7 ba.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 34), transition_delay=tdelay, text=ba.Lstr(resource='demoText', fallback_resource='mainMenu.demoMenuText'), flatness=1.0, scale=1.2, h_align='center', v_align='center', shadow=1.0) h = self._width * 0.5 - b_space tdelay = t_delay_base + t_delay_scale * 0.7 self._b1 = btn = ba.buttonwidget(parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=ba.Call( self._do_game, 'easy'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square') ba.textwidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=ba.Lstr(resource=self._r + '.easyText'), scale=1.3, h_align='center', v_align='center') ba.imagewidget(parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=ba.gettexture('doomShroomPreview'), model_opaque=model_opaque, model_transparent=model_transparent, mask_texture=mask_tex) h = self._width * 0.5 tdelay = t_delay_base + t_delay_scale * 0.65 self._b2 = btn = ba.buttonwidget(parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=ba.Call( self._do_game, 'medium'), position=(h - b_width * 0.5, b_v), label='', button_type='square', transition_delay=tdelay) ba.textwidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=ba.Lstr(resource=self._r + '.mediumText'), scale=1.3, h_align='center', v_align='center') ba.imagewidget(parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=ba.gettexture('footballStadiumPreview'), model_opaque=model_opaque, model_transparent=model_transparent, mask_texture=mask_tex) h = self._width * 0.5 + b_space tdelay = t_delay_base + t_delay_scale * 0.6 self._b3 = btn = ba.buttonwidget(parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=ba.Call( self._do_game, 'hard'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square') ba.textwidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text='Hard', scale=1.3, h_align='center', v_align='center') ba.imagewidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(img_width, 0.5 * img_width), position=(h - img_width * 0.5, img_v), texture=ba.gettexture('courtyardPreview'), model_opaque=model_opaque, model_transparent=model_transparent, mask_texture=mask_tex) if not ba.app.did_menu_intro: ba.app.did_menu_intro = True self._b4: Optional[ba.Widget] self._b5: Optional[ba.Widget] self._b6: Optional[ba.Widget] if bool(False): ba.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 44), transition_delay=tdelay, text=ba.Lstr(resource=self._r + '.versusExamplesText'), flatness=1.0, scale=1.2, h_align='center', v_align='center', shadow=1.0) h = self._width * 0.5 - b_space tdelay = t_delay_base + t_delay_scale * 0.7 self._b4 = btn = ba.buttonwidget(parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=ba.Call( self._do_game, 'ctf'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square') ba.textwidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=ba.Lstr(translate=('gameNames', 'Capture the Flag')), scale=1.3, h_align='center', v_align='center') ba.imagewidget(parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=ba.gettexture('bridgitPreview'), model_opaque=model_opaque, model_transparent=model_transparent, mask_texture=mask_tex) h = self._width * 0.5 tdelay = t_delay_base + t_delay_scale * 0.65 self._b5 = btn = ba.buttonwidget(parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=ba.Call( self._do_game, 'hockey'), position=(h - b_width * 0.5, b_v), label='', button_type='square', transition_delay=tdelay) ba.textwidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=ba.Lstr(translate=('gameNames', 'Hockey')), scale=1.3, h_align='center', v_align='center') ba.imagewidget(parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=ba.gettexture('hockeyStadiumPreview'), model_opaque=model_opaque, model_transparent=model_transparent, mask_texture=mask_tex) h = self._width * 0.5 + b_space tdelay = t_delay_base + t_delay_scale * 0.6 self._b6 = btn = ba.buttonwidget(parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=ba.Call( self._do_game, 'epic'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square') ba.textwidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=ba.Lstr(resource=self._r + '.epicModeText'), scale=1.3, h_align='center', v_align='center') ba.imagewidget(parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(img_width, 0.5 * img_width), position=(h - img_width * 0.5, img_v), texture=ba.gettexture('tipTopPreview'), model_opaque=model_opaque, model_transparent=model_transparent, mask_texture=mask_tex) else: self._b4 = self._b5 = self._b6 = None self._b7: Optional[ba.Widget] uiscale = ba.app.uiscale if bool(False): self._b7 = ba.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, 50), color=(0.45, 0.55, 0.45), textcolor=(0.7, 0.8, 0.7), scale=0.5, position=((self._width * 0.5 - 37.5, y_extra + 120) if not self._show_multiplayer else (self._width + 100, y_extra + (140 if uiscale is ba.UIScale.SMALL else 120))), transition_delay=tdelay, label=ba.Lstr(resource=self._r + '.fullMenuText'), on_activate_call=self._do_full_menu) else: self._b7 = None self._restore_state() self._update() self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True)
def __init__(self, gameclass: Type[ba.GameActivity], sessiontype: Type[ba.Session], config: Dict[str, Any], edit_info: Dict[str, Any], completion_call: Callable[[Optional[Dict[str, Any]]], Any], transition: str = 'in_right'): from ba.internal import get_filtered_map_name self._gameclass = gameclass self._sessiontype = sessiontype self._config = config self._completion_call = completion_call self._edit_info = edit_info self._maps: List[Tuple[str, ba.Texture]] = [] try: self._previous_map = get_filtered_map_name( config['settings']['map']) except Exception: self._previous_map = '' uiscale = ba.app.uiscale width = 715 if uiscale is ba.UIScale.SMALL else 615 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 height = (400 if uiscale is ba.UIScale.SMALL else 480 if uiscale is ba.UIScale.MEDIUM else 600) top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, scale=(2.17 if uiscale is ba.UIScale.SMALL else 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -27) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = btn = ba.buttonwidget( parent=self._root_widget, position=(38 + x_inset, height - 67), size=(140, 50), scale=0.9, text_scale=1.0, autoselect=True, label=ba.Lstr(resource='cancelText'), on_activate_call=self._cancel) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.textwidget(parent=self._root_widget, position=(width * 0.5, height - 46), size=(0, 0), maxwidth=260, scale=1.1, text=ba.Lstr(resource='mapSelectTitleText', subs=[('${GAME}', self._gameclass.get_display_string()) ]), color=ba.app.title_color, h_align='center', v_align='center') v = height - 70 self._scroll_width = width - (80 + 2 * x_inset) self._scroll_height = height - 140 self._scrollwidget = ba.scrollwidget( parent=self._root_widget, position=(40 + x_inset, v - self._scroll_height), size=(self._scroll_width, self._scroll_height)) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._subcontainer: Optional[ba.Widget] = None self._refresh()
def _refresh(self, select_get_more_maps_button: bool = False) -> None: # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-locals from ba.internal import (get_unowned_maps, get_map_class, get_map_display_string) # Kill old. if self._subcontainer is not None: self._subcontainer.delete() model_opaque = ba.getmodel('level_select_button_opaque') model_transparent = ba.getmodel('level_select_button_transparent') self._maps = [] map_list = self._gameclass.get_supported_maps(self._sessiontype) map_list_sorted = list(map_list) map_list_sorted.sort() unowned_maps = get_unowned_maps() for mapname in map_list_sorted: # Disallow ones we don't own. if mapname in unowned_maps: continue map_tex_name = (get_map_class(mapname).get_preview_texture_name()) if map_tex_name is not None: try: map_tex = ba.gettexture(map_tex_name) self._maps.append((mapname, map_tex)) except Exception: print(f'Invalid map preview texture: "{map_tex_name}".') else: print('Error: no map preview texture for map:', mapname) count = len(self._maps) columns = 2 rows = int(math.ceil(float(count) / columns)) button_width = 220 button_height = button_width * 0.5 button_buffer_h = 16 button_buffer_v = 19 self._sub_width = self._scroll_width * 0.95 self._sub_height = 5 + rows * (button_height + 2 * button_buffer_v) + 100 self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), background=False) index = 0 mask_texture = ba.gettexture('mapPreviewMask') h_offs = 130 if len(self._maps) == 1 else 0 for y in range(rows): for x in range(columns): pos = (x * (button_width + 2 * button_buffer_h) + button_buffer_h + h_offs, self._sub_height - (y + 1) * (button_height + 2 * button_buffer_v) + 12) btn = ba.buttonwidget(parent=self._subcontainer, button_type='square', size=(button_width, button_height), autoselect=True, texture=self._maps[index][1], mask_texture=mask_texture, model_opaque=model_opaque, model_transparent=model_transparent, label='', color=(1, 1, 1), on_activate_call=ba.Call( self._select_with_delay, self._maps[index][0]), position=pos) if x == 0: ba.widget(edit=btn, left_widget=self._cancel_button) if y == 0: ba.widget(edit=btn, up_widget=self._cancel_button) if x == columns - 1 and ba.app.toolbars: ba.widget( edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) if self._maps[index][0] == self._previous_map: ba.containerwidget(edit=self._subcontainer, selected_child=btn, visible_child=btn) name = get_map_display_string(self._maps[index][0]) ba.textwidget(parent=self._subcontainer, text=name, position=(pos[0] + button_width * 0.5, pos[1] - 12), size=(0, 0), scale=0.5, maxwidth=button_width, draw_controller=btn, h_align='center', v_align='center', color=(0.8, 0.8, 0.8, 0.8)) index += 1 if index >= count: break if index >= count: break self._get_more_maps_button = btn = ba.buttonwidget( parent=self._subcontainer, size=(self._sub_width * 0.8, 60), position=(self._sub_width * 0.1, 30), label=ba.Lstr(resource='mapSelectGetMoreMapsText'), on_activate_call=self._on_store_press, color=(0.6, 0.53, 0.63), textcolor=(0.75, 0.7, 0.8), autoselect=True) ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30) if select_get_more_maps_button: ba.containerwidget(edit=self._subcontainer, selected_child=btn, visible_child=btn)
def _refresh(self) -> None: # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements from bastd.ui import confirm from bastd.ui.store.button import StoreButton # Clear everything that was there. children = self._root_widget.get_children() for child in children: child.delete() self._tdelay = 0.0 self._t_delay_inc = 0.0 self._t_delay_play = 0.0 self._button_width = 200.0 self._button_height = 45.0 self._r = 'mainMenu' app = ba.app self._have_quit_button = (app.interface_type == 'large' or (app.platform == 'windows' and app.subplatform == 'oculus')) self._have_store_button = not self._in_game self._have_settings_button = ((not self._in_game or not app.toolbar_test) and not self._is_kiosk) self._input_device = input_device = _ba.get_ui_input_device() self._input_player = input_device.player if input_device else None self._connected_to_remote_player = ( input_device.is_connected_to_remote_player() if input_device else False) positions: List[Tuple[float, float, float]] = [] self._p_index = 0 if self._in_game: h, v, scale = self._refresh_in_game(positions) else: h, v, scale = self._refresh_not_in_game(positions) if self._have_settings_button: h, v, scale = positions[self._p_index] self._p_index += 1 self._settings_button = ba.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), size=(self._button_width, self._button_height), scale=scale, autoselect=self._use_autoselect, label=ba.Lstr(resource=self._r + '.settingsText'), transition_delay=self._tdelay, on_activate_call=self._settings) # Scattered eggs on easter. if _ba.get_account_misc_read_val('easter', False) and not self._in_game: icon_size = 34 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 - 15, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), texture=ba.gettexture('egg3'), tilt_scale=0.0) self._tdelay += self._t_delay_inc if self._in_game: h, v, scale = positions[self._p_index] self._p_index += 1 # If we're in a replay, we have a 'Leave Replay' button. if _ba.is_in_replay(): ba.buttonwidget(parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, size=(self._button_width, self._button_height), autoselect=self._use_autoselect, label=ba.Lstr(resource='replayEndText'), on_activate_call=self._confirm_end_replay) elif _ba.get_foreground_host_session() is not None: ba.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, size=(self._button_width, self._button_height), autoselect=self._use_autoselect, label=ba.Lstr(resource=self._r + '.endGameText'), on_activate_call=self._confirm_end_game) # Assume we're in a client-session. else: ba.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, size=(self._button_width, self._button_height), autoselect=self._use_autoselect, label=ba.Lstr(resource=self._r + '.leavePartyText'), on_activate_call=self._confirm_leave_party) self._store_button: Optional[ba.Widget] if self._have_store_button: this_b_width = self._button_width h, v, scale = positions[self._p_index] self._p_index += 1 sbtn = self._store_button_instance = StoreButton( parent=self._root_widget, position=(h - this_b_width * 0.5 * scale, v), size=(this_b_width, self._button_height), scale=scale, on_activate_call=ba.WeakCall(self._on_store_pressed), sale_scale=1.3, transition_delay=self._tdelay) self._store_button = store_button = sbtn.get_button() icon_size = (55 if ba.app.small_ui else 55 if ba.app.med_ui else 70) ba.imagewidget( parent=self._root_widget, position=(h - icon_size * 0.5, v + self._button_height * scale - icon_size * 0.23), transition_delay=self._tdelay, size=(icon_size, icon_size), texture=ba.gettexture(self._store_char_tex), tilt_scale=0.0, draw_controller=store_button) self._tdelay += self._t_delay_inc else: self._store_button = None self._quit_button: Optional[ba.Widget] if not self._in_game and self._have_quit_button: h, v, scale = positions[self._p_index] self._p_index += 1 self._quit_button = quit_button = ba.buttonwidget( parent=self._root_widget, autoselect=self._use_autoselect, position=(h - self._button_width * 0.5 * scale, v), size=(self._button_width, self._button_height), scale=scale, label=ba.Lstr(resource=self._r + ('.quitText' if 'Mac' in ba.app.user_agent_string else '.exitGameText')), on_activate_call=self._quit, transition_delay=self._tdelay) # Scattered eggs on easter. if _ba.get_account_misc_read_val('easter', False): icon_size = 30 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 25, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), texture=ba.gettexture('egg1'), tilt_scale=0.0) ba.containerwidget(edit=self._root_widget, cancel_button=quit_button) self._tdelay += self._t_delay_inc else: self._quit_button = None # If we're not in-game, have no quit button, and this is android, # we want back presses to quit our activity. if (not self._in_game and not self._have_quit_button and ba.app.platform == 'android'): def _do_quit() -> None: confirm.QuitWindow(swish=True, back=True) ba.containerwidget(edit=self._root_widget, on_cancel_call=_do_quit) # Add speed-up/slow-down buttons for replays. # (ideally this should be part of a fading-out playback bar like most # media players but this works for now). if _ba.is_in_replay(): b_size = 50.0 b_buffer = 10.0 t_scale = 0.75 if ba.app.small_ui: b_size *= 0.6 b_buffer *= 1.0 v_offs = -40 t_scale = 0.5 elif ba.app.med_ui: v_offs = -70 else: v_offs = -100 self._replay_speed_text = ba.textwidget( parent=self._root_widget, text=ba.Lstr(resource='watchWindow.playbackSpeedText', subs=[('${SPEED}', str(1.23))]), position=(h, v + v_offs + 7 * t_scale), h_align='center', v_align='center', size=(0, 0), scale=t_scale) # Update to current value. self._change_replay_speed(0) # Keep updating in a timer in case it gets changed elsewhere. self._change_replay_speed_timer = ba.Timer( 0.25, ba.WeakCall(self._change_replay_speed, 0), timetype=ba.TimeType.REAL, repeat=True) btn = ba.buttonwidget(parent=self._root_widget, position=(h - b_size - b_buffer, v - b_size - b_buffer + v_offs), button_type='square', size=(b_size, b_size), label='', autoselect=True, on_activate_call=ba.Call( self._change_replay_speed, -1)) ba.textwidget( parent=self._root_widget, draw_controller=btn, text='-', position=(h - b_size * 0.5 - b_buffer, v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), h_align='center', v_align='center', size=(0, 0), scale=3.0 * t_scale) btn = ba.buttonwidget( parent=self._root_widget, position=(h + b_buffer, v - b_size - b_buffer + v_offs), button_type='square', size=(b_size, b_size), label='', autoselect=True, on_activate_call=ba.Call(self._change_replay_speed, 1)) ba.textwidget( parent=self._root_widget, draw_controller=btn, text='+', position=(h + b_size * 0.5 + b_buffer, v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), h_align='center', v_align='center', size=(0, 0), scale=3.0 * t_scale)
def _set_highlight(self, color: Tuple[float, float, float]) -> None: self._highlight = color if self._highlight_button: ba.buttonwidget(edit=self._highlight_button, color=color)
def _refresh_not_in_game( self, positions: List[Tuple[float, float, float]]) -> Tuple[float, float, float]: # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements if not ba.app.did_menu_intro: self._tdelay = 2.0 self._t_delay_inc = 0.02 self._t_delay_play = 1.7 ba.app.did_menu_intro = True self._width = 400.0 self._height = 200.0 enable_account_button = True account_type_name: Union[str, ba.Lstr] if _ba.get_account_state() == 'signed_in': account_type_name = _ba.get_account_display_string() account_type_icon = None account_textcolor = (1.0, 1.0, 1.0) else: account_type_name = ba.Lstr( resource='notSignedInText', fallback_resource='accountSettingsWindow.titleText') account_type_icon = None account_textcolor = (1.0, 0.2, 0.2) account_type_icon_color = (1.0, 1.0, 1.0) account_type_call = self._show_account_window account_type_enable_button_sound = True b_count = 4 # play, help, credits, settings if enable_account_button: b_count += 1 if self._have_quit_button: b_count += 1 if self._have_store_button: b_count += 1 if ba.app.small_ui: root_widget_scale = 1.6 play_button_width = self._button_width * 0.65 play_button_height = self._button_height * 1.1 small_button_scale = 0.51 if b_count > 6 else 0.63 button_y_offs = -20.0 button_y_offs2 = -60.0 self._button_height *= 1.3 button_spacing = 1.04 elif ba.app.med_ui: root_widget_scale = 1.3 play_button_width = self._button_width * 0.65 play_button_height = self._button_height * 1.1 small_button_scale = 0.6 button_y_offs = -55.0 button_y_offs2 = -75.0 self._button_height *= 1.25 button_spacing = 1.1 else: root_widget_scale = 1.0 play_button_width = self._button_width * 0.65 play_button_height = self._button_height * 1.1 small_button_scale = 0.75 button_y_offs = -80.0 button_y_offs2 = -100.0 self._button_height *= 1.2 button_spacing = 1.1 spc = self._button_width * small_button_scale * button_spacing ba.containerwidget(edit=self._root_widget, size=(self._width, self._height), background=False, scale=root_widget_scale) assert not positions positions.append((self._width * 0.5, button_y_offs, 1.7)) x_offs = self._width * 0.5 - (spc * (b_count - 1) * 0.5) + (spc * 0.5) for i in range(b_count - 1): positions.append( (x_offs + spc * i - 1.0, button_y_offs + button_y_offs2, small_button_scale)) # In kiosk mode, provide a button to get back to the kiosk menu. if ba.app.kiosk_mode: h, v, scale = positions[self._p_index] this_b_width = self._button_width * 0.4 * scale demo_menu_delay = 0.0 if self._t_delay_play == 0.0 else max( 0, self._t_delay_play + 0.1) self._demo_menu_button = ba.buttonwidget( parent=self._root_widget, position=(self._width * 0.5 - this_b_width * 0.5, v + 90), size=(this_b_width, 45), autoselect=True, color=(0.45, 0.55, 0.45), textcolor=(0.7, 0.8, 0.7), label=ba.Lstr(resource=self._r + '.demoMenuText'), transition_delay=demo_menu_delay, on_activate_call=self._demo_menu_press) else: self._demo_menu_button = None foof = (-1 if ba.app.small_ui else 1 if ba.app.med_ui else 3) h, v, scale = positions[self._p_index] v = v + foof gather_delay = 0.0 if self._t_delay_play == 0.0 else max( 0.0, self._t_delay_play + 0.1) assert play_button_width is not None assert play_button_height is not None this_h = h - play_button_width * 0.5 * scale - 40 * scale this_b_width = self._button_width * 0.25 * scale this_b_height = self._button_height * 0.82 * scale self._gather_button = btn = ba.buttonwidget( parent=self._root_widget, position=(this_h - this_b_width * 0.5, v), size=(this_b_width, this_b_height), autoselect=self._use_autoselect, button_type='square', label='', transition_delay=gather_delay, on_activate_call=self._gather_press) ba.textwidget(parent=self._root_widget, position=(this_h, v + self._button_height * 0.33), size=(0, 0), scale=0.75, transition_delay=gather_delay, draw_controller=btn, color=(0.75, 1.0, 0.7), maxwidth=self._button_width * 0.33, text=ba.Lstr(resource='gatherWindow.titleText'), h_align='center', v_align='center') icon_size = this_b_width * 0.6 ba.imagewidget(parent=self._root_widget, size=(icon_size, icon_size), draw_controller=btn, transition_delay=gather_delay, position=(this_h - 0.5 * icon_size, v + 0.31 * this_b_height), texture=ba.gettexture('usersButton')) # Play button. h, v, scale = positions[self._p_index] self._p_index += 1 self._start_button = start_button = ba.buttonwidget( parent=self._root_widget, position=(h - play_button_width * 0.5 * scale, v), size=(play_button_width, play_button_height), autoselect=self._use_autoselect, scale=scale, text_res_scale=2.0, label=ba.Lstr(resource='playText'), transition_delay=self._t_delay_play, on_activate_call=self._play_press) ba.containerwidget(edit=self._root_widget, start_button=start_button, selected_child=start_button) v = v + foof watch_delay = 0.0 if self._t_delay_play == 0.0 else max( 0.0, self._t_delay_play - 0.1) this_h = h + play_button_width * 0.5 * scale + 40 * scale this_b_width = self._button_width * 0.25 * scale this_b_height = self._button_height * 0.82 * scale self._watch_button = btn = ba.buttonwidget( parent=self._root_widget, position=(this_h - this_b_width * 0.5, v), size=(this_b_width, this_b_height), autoselect=self._use_autoselect, button_type='square', label='', transition_delay=watch_delay, on_activate_call=self._watch_press) ba.textwidget(parent=self._root_widget, position=(this_h, v + self._button_height * 0.33), size=(0, 0), scale=0.75, transition_delay=watch_delay, color=(0.75, 1.0, 0.7), draw_controller=btn, maxwidth=self._button_width * 0.33, text=ba.Lstr(resource='watchWindow.titleText'), h_align='center', v_align='center') icon_size = this_b_width * 0.55 ba.imagewidget(parent=self._root_widget, size=(icon_size, icon_size), draw_controller=btn, transition_delay=watch_delay, position=(this_h - 0.5 * icon_size, v + 0.33 * this_b_height), texture=ba.gettexture('tv')) if not self._in_game and enable_account_button: this_b_width = self._button_width h, v, scale = positions[self._p_index] self._p_index += 1 self._gc_button = ba.buttonwidget( parent=self._root_widget, position=(h - this_b_width * 0.5 * scale, v), size=(this_b_width, self._button_height), scale=scale, label=account_type_name, autoselect=self._use_autoselect, on_activate_call=account_type_call, textcolor=account_textcolor, icon=account_type_icon, icon_color=account_type_icon_color, transition_delay=self._tdelay, enable_sound=account_type_enable_button_sound) # Scattered eggs on easter. if _ba.get_account_misc_read_val('easter', False) and not self._in_game: icon_size = 32 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 35, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), texture=ba.gettexture('egg2'), tilt_scale=0.0) self._tdelay += self._t_delay_inc else: self._gc_button = None # How-to-play button. h, v, scale = positions[self._p_index] self._p_index += 1 btn = ba.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, autoselect=self._use_autoselect, size=(self._button_width, self._button_height), label=ba.Lstr(resource=self._r + '.howToPlayText'), transition_delay=self._tdelay, on_activate_call=self._howtoplay) self._how_to_play_button = btn # Scattered eggs on easter. if _ba.get_account_misc_read_val('easter', False) and not self._in_game: icon_size = 28 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 30, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), texture=ba.gettexture('egg4'), tilt_scale=0.0) # Credits button. self._tdelay += self._t_delay_inc h, v, scale = positions[self._p_index] self._p_index += 1 self._credits_button = ba.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), size=(self._button_width, self._button_height), autoselect=self._use_autoselect, label=ba.Lstr(resource=self._r + '.creditsText'), scale=scale, transition_delay=self._tdelay, on_activate_call=self._credits) self._tdelay += self._t_delay_inc return h, v, scale
def __init__(self, parent: ba.Widget, position: Tuple[float, float] = (0.0, 0.0), delegate: Any = None, scale: float = None, offset: Tuple[float, float] = (0.0, 0.0), tint_color: Sequence[float] = (1.0, 1.0, 1.0), tint2_color: Sequence[float] = (1.0, 1.0, 1.0), selected_icon: str = None): # pylint: disable=too-many-locals from ba.internal import get_purchased_icons del parent # unused here del tint_color # unused_here del tint2_color # unused here uiscale = ba.app.uiscale if scale is None: scale = (1.85 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False self._icons = [ba.charstr(ba.SpecialChar.LOGO)] + get_purchased_icons() count = len(self._icons) columns = 4 rows = int(math.ceil(float(count) / columns)) button_width = 50 button_height = 50 button_buffer_h = 10 button_buffer_v = 5 self._width = (10 + columns * (button_width + 2 * button_buffer_h) * (1.0 / 0.95) * (1.0 / 0.8)) self._height = (self._width * (0.8 if uiscale is ba.UIScale.SMALL else 1.06)) self._scroll_width = self._width * 0.8 self._scroll_height = self._height * 0.8 self._scroll_position = ((self._width - self._scroll_width) * 0.5, (self._height - self._scroll_height) * 0.5) # creates our _root_widget popup.PopupWindow.__init__(self, position=position, size=(self._width, self._height), scale=scale, bg_color=(0.5, 0.5, 0.5), offset=offset, focus_position=self._scroll_position, focus_size=(self._scroll_width, self._scroll_height)) self._scrollwidget = ba.scrollwidget(parent=self.root_widget, size=(self._scroll_width, self._scroll_height), color=(0.55, 0.55, 0.55), highlight=False, position=self._scroll_position) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._sub_width = self._scroll_width * 0.95 self._sub_height = 5 + rows * (button_height + 2 * button_buffer_v) + 100 self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), background=False) index = 0 for y in range(rows): for x in range(columns): pos = (x * (button_width + 2 * button_buffer_h) + button_buffer_h, self._sub_height - (y + 1) * (button_height + 2 * button_buffer_v) + 0) btn = ba.buttonwidget(parent=self._subcontainer, button_type='square', size=(button_width, button_height), autoselect=True, text_scale=1.2, label='', color=(0.65, 0.65, 0.65), on_activate_call=ba.Call( self._select_icon, self._icons[index]), position=pos) ba.textwidget(parent=self._subcontainer, h_align='center', v_align='center', size=(0, 0), position=(pos[0] + 0.5 * button_width - 1, pos[1] + 15), draw_controller=btn, text=self._icons[index], scale=1.8) ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) if self._icons[index] == selected_icon: ba.containerwidget(edit=self._subcontainer, selected_child=btn, visible_child=btn) index += 1 if index >= count: break if index >= count: break self._get_more_icons_button = btn = ba.buttonwidget( parent=self._subcontainer, size=(self._sub_width * 0.8, 60), position=(self._sub_width * 0.1, 30), label=ba.Lstr(resource='editProfileWindow.getMoreIconsText'), on_activate_call=self._on_store_press, color=(0.6, 0.6, 0.6), textcolor=(0.8, 0.8, 0.8), autoselect=True) ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
def __init__(self, parent: ba.Widget, configkey: str, position: tuple[float, float], minval: float = 0.0, maxval: float = 100.0, increment: float = 1.0, callback: Callable[[float], Any] = None, xoffset: float = 0.0, displayname: Union[str, ba.Lstr] = None, changesound: bool = True, textscale: float = 1.0): if displayname is None: displayname = configkey self._configkey = configkey self._minval = minval self._maxval = maxval self._increment = increment self._callback = callback self._value = ba.app.config.resolve(configkey) self.nametext = ba.textwidget(parent=parent, position=position, size=(100, 30), text=displayname, maxwidth=160 + xoffset, color=(0.8, 0.8, 0.8, 1.0), h_align='left', v_align='center', scale=textscale) self.valuetext = ba.textwidget(parent=parent, position=(246 + xoffset, position[1]), size=(60, 28), editable=False, color=(0.3, 1.0, 0.3, 1.0), h_align='right', v_align='center', text=str(self._value), padding=2) self.minusbutton = ba.buttonwidget( parent=parent, position=(330 + xoffset, position[1]), size=(28, 28), label='-', autoselect=True, on_activate_call=ba.Call(self._down), repeat=True, enable_sound=changesound) self.plusbutton = ba.buttonwidget(parent=parent, position=(380 + xoffset, position[1]), size=(28, 28), label='+', autoselect=True, on_activate_call=ba.Call(self._up), repeat=True, enable_sound=changesound) # Complain if we outlive our widgets. ba.uicleanupcheck(self, self.nametext) self._update_display()
def __init__(self, address: str): # in some cases we might want to show it as a qr code # (for long URLs especially) app = ba.app uiscale = app.ui.uiscale if app.platform == 'android' and app.subplatform == 'alibaba': self._width = 500 self._height = 500 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_right', scale=(1.25 if uiscale is ba.UIScale.SMALL else 1.25 if uiscale is ba.UIScale.MEDIUM else 1.25))) self._cancel_button = ba.buttonwidget( parent=self._root_widget, position=(50, self._height - 30), size=(50, 50), scale=0.6, label='', color=(0.6, 0.5, 0.6), on_activate_call=self._done, autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) qr_size = 400 ba.imagewidget(parent=self._root_widget, position=(self._width * 0.5 - qr_size * 0.5, self._height * 0.5 - qr_size * 0.5), size=(qr_size, qr_size), texture=_ba.get_qrcode_texture(address)) ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) else: # show it as a simple string... self._width = 800 self._height = 200 self._root_widget = ba.containerwidget( size=(self._width, self._height + 40), transition='in_right', scale=(1.25 if uiscale is ba.UIScale.SMALL else 1.25 if uiscale is ba.UIScale.MEDIUM else 1.25)) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 10), size=(0, 0), color=ba.app.ui.title_color, h_align='center', v_align='center', text=ba.Lstr(resource='directBrowserToURLText'), maxwidth=self._width * 0.95) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height * 0.5 + 29), size=(0, 0), scale=1.3, color=ba.app.ui.infotextcolor, h_align='center', v_align='center', text=address, maxwidth=self._width * 0.95) button_width = 200 btn = ba.buttonwidget(parent=self._root_widget, position=(self._width * 0.5 - button_width * 0.5, 20), size=(button_width, 65), label=ba.Lstr(resource='doneText'), on_activate_call=self._done) # we have no 'cancel' button but still want to be able to # hit back/escape/etc to leave.. ba.containerwidget(edit=self._root_widget, selected_child=btn, start_button=btn, on_cancel_call=btn.activate)
def __init__(self, existing_soundtrack: Optional[Union[str, Dict[str, Any]]], transition: str = 'in_right'): # pylint: disable=too-many-statements bs_config = ba.app.config self._r = 'editSoundtrackWindow' self._folder_tex = ba.gettexture('folder') self._file_tex = ba.gettexture('file') self._width = 848 if ba.app.small_ui else 648 x_inset = 100 if ba.app.small_ui else 0 self._height = (395 if ba.app.small_ui else 450 if ba.app.med_ui else 560) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, scale=(2.08 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0), stack_offset=(0, -48) if ba.app.small_ui else ( 0, 15) if ba.app.med_ui else (0, 0))) cancel_button = ba.buttonwidget(parent=self._root_widget, position=(38 + x_inset, self._height - 60), size=(160, 60), autoselect=True, label=ba.Lstr(resource='cancelText'), scale=0.8) save_button = ba.buttonwidget(parent=self._root_widget, position=(self._width - (168 + x_inset), self._height - 60), autoselect=True, size=(160, 60), label=ba.Lstr(resource='saveText'), scale=0.8) ba.widget(edit=save_button, left_widget=cancel_button) ba.widget(edit=cancel_button, right_widget=save_button) ba.textwidget( parent=self._root_widget, position=(0, self._height - 50), size=(self._width, 25), text=ba.Lstr(resource=self._r + ('.editSoundtrackText' if existing_soundtrack is not None else '.newSoundtrackText')), color=ba.app.title_color, h_align="center", v_align="center", maxwidth=280) v = self._height - 110 if 'Soundtracks' not in bs_config: bs_config['Soundtracks'] = {} self._soundtrack_name: Optional[str] self._existing_soundtrack_name: Optional[str] if existing_soundtrack is not None: # if they passed just a name, pull info from that soundtrack if isinstance(existing_soundtrack, str): self._soundtrack = copy.deepcopy( bs_config['Soundtracks'][existing_soundtrack]) self._soundtrack_name = existing_soundtrack self._existing_soundtrack_name = existing_soundtrack self._last_edited_song_type = None else: # otherwise they can pass info on an in-progress edit self._soundtrack = existing_soundtrack['soundtrack'] self._soundtrack_name = existing_soundtrack['name'] self._existing_soundtrack_name = ( existing_soundtrack['existing_name']) self._last_edited_song_type = ( existing_soundtrack['last_edited_song_type']) else: self._soundtrack_name = None self._existing_soundtrack_name = None self._soundtrack = {} self._last_edited_song_type = None ba.textwidget(parent=self._root_widget, text=ba.Lstr(resource=self._r + '.nameText'), maxwidth=80, scale=0.8, position=(105 + x_inset, v + 19), color=(0.8, 0.8, 0.8, 0.5), size=(0, 0), h_align='right', v_align='center') # if there's no initial value, find a good initial unused name if existing_soundtrack is None: i = 1 st_name_text = ba.Lstr(resource=self._r + '.newSoundtrackNameText').evaluate() if '${COUNT}' not in st_name_text: # make sure we insert number *somewhere* st_name_text = st_name_text + ' ${COUNT}' while True: self._soundtrack_name = st_name_text.replace( '${COUNT}', str(i)) if self._soundtrack_name not in bs_config['Soundtracks']: break i += 1 self._text_field = ba.textwidget( parent=self._root_widget, position=(120 + x_inset, v - 5), size=(self._width - (160 + 2 * x_inset), 43), text=self._soundtrack_name, h_align="left", v_align="center", max_chars=32, autoselect=True, description=ba.Lstr(resource=self._r + '.nameText'), editable=True, padding=4, on_return_press_call=self._do_it_with_sound) scroll_height = self._height - 180 self._scrollwidget = scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, position=(40 + x_inset, v - (scroll_height + 10)), size=(self._width - (80 + 2 * x_inset), scroll_height), simple_culling_v=10) ba.widget(edit=self._text_field, down_widget=self._scrollwidget) self._col = ba.columnwidget(parent=scrollwidget) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True, claims_tab=True, selection_loop_to_parent=True) ba.containerwidget(edit=self._col, claims_left_right=True, claims_tab=True, selection_loop_to_parent=True) self._song_type_buttons: Dict[str, ba.Widget] = {} self._refresh() ba.buttonwidget(edit=cancel_button, on_activate_call=self._cancel) ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button) ba.buttonwidget(edit=save_button, on_activate_call=self._do_it) ba.containerwidget(edit=self._root_widget, start_button=save_button) ba.widget(edit=self._text_field, up_widget=cancel_button) ba.widget(edit=cancel_button, down_widget=self._text_field)
def __init__(self, textwidget: ba.Widget, label: str, max_chars: int): self._target_text = textwidget self._width = 700 self._height = 400 uiscale = ba.app.ui.uiscale top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( parent=_ba.get_special_widget('overlay_stack'), size=(self._width, self._height + top_extra), transition='in_scale', scale_origin_stack_offset=self._target_text. get_screen_space_center(), scale=(2.0 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, 0) if uiscale is ba.UIScale.SMALL else ( 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0))) self._done_button = ba.buttonwidget(parent=self._root_widget, position=(self._width - 200, 44), size=(140, 60), autoselect=True, label=ba.Lstr(resource='doneText'), on_activate_call=self._done) ba.containerwidget(edit=self._root_widget, on_cancel_call=self._cancel, start_button=self._done_button) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 41), size=(0, 0), scale=0.95, text=label, maxwidth=self._width - 140, color=ba.app.ui.title_color, h_align='center', v_align='center') self._text_field = ba.textwidget( parent=self._root_widget, position=(70, self._height - 116), max_chars=max_chars, text=cast(str, ba.textwidget(query=self._target_text)), on_return_press_call=self._done, autoselect=True, size=(self._width - 140, 55), v_align='center', editable=True, maxwidth=self._width - 175, force_internal_editing=True, always_show_carat=True) self._key_color_lit = (1.4, 1.2, 1.4) self._key_color = (0.69, 0.6, 0.74) self._key_color_dark = (0.55, 0.55, 0.71) self._shift_button: Optional[ba.Widget] = None self._backspace_button: Optional[ba.Widget] = None self._space_button: Optional[ba.Widget] = None self._double_press_shift = False self._num_mode_button: Optional[ba.Widget] = None self._emoji_button: Optional[ba.Widget] = None self._char_keys: List[ba.Widget] = [] self._keyboard_index = 0 self._last_space_press = 0.0 self._double_space_interval = 0.3 self._keyboard: ba.Keyboard self._chars: List[str] self._modes: List[str] self._mode: str self._mode_index: int self._load_keyboard()
def __init__(self, window: CoopBrowserWindow, parent: ba.Widget, game: str, x: float, y: float, select: bool, row: str): # pylint: disable=too-many-statements # pylint: disable=too-many-locals from ba.internal import getcampaign self._game = game sclx = 195.0 scly = 195.0 campaignname, levelname = game.split(':') # Hack: The Last Stand doesn't actually exist in the easy # tourney. We just want it for display purposes. Map it to # the hard-mode version. if game == 'Easy:The Last Stand': campaignname = 'Default' rating: Optional[float] campaign = getcampaign(campaignname) rating = campaign.getlevel(levelname).rating if game == 'Easy:The Last Stand': rating = None if rating is None or rating == 0.0: stars = 0 elif rating >= 9.5: stars = 3 elif rating >= 7.5: stars = 2 else: stars = 1 self._button = btn = ba.buttonwidget( parent=parent, position=(x + 23, y + 4), size=(sclx, scly), label='', on_activate_call=ba.Call(window.run, game), button_type='square', autoselect=True, on_select_call=ba.Call(window.sel_change, row, game)) ba.widget(edit=btn, show_buffer_bottom=50, show_buffer_top=50, show_buffer_left=400, show_buffer_right=200) if select: ba.containerwidget(edit=parent, selected_child=btn, visible_child=btn) image_width = sclx * 0.85 * 0.75 self._preview_widget = ba.imagewidget( parent=parent, draw_controller=btn, position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 104), size=(image_width, image_width * 0.5), model_transparent=window.lsbt, model_opaque=window.lsbo, texture=campaign.getlevel(levelname).get_preview_texture(), mask_texture=ba.gettexture('mapPreviewMask')) translated = campaign.getlevel(levelname).displayname self._achievements = ba.app.ach.achievements_for_coop_level(game) self._name_widget = ba.textwidget(parent=parent, draw_controller=btn, position=(x + 20 + sclx * 0.5, y + scly - 27), size=(0, 0), h_align='center', text=translated, v_align='center', maxwidth=sclx * 0.76, scale=0.85) xscl = x + (67 if self._achievements else 50) yscl = y + scly - (137 if self._achievements else 157) starscale = 35.0 if self._achievements else 45.0 self._star_widgets: list[ba.Widget] = [] for _i in range(stars): imw = ba.imagewidget(parent=parent, draw_controller=btn, position=(xscl, yscl), size=(starscale, starscale), texture=window.star_tex) self._star_widgets.append(imw) xscl += starscale for _i in range(3 - stars): ba.imagewidget(parent=parent, draw_controller=btn, position=(xscl, yscl), size=(starscale, starscale), color=(0, 0, 0), texture=window.star_tex, opacity=0.3) xscl += starscale xach = x + 69 yach = y + scly - 168 a_scale = 30.0 self._achievement_widgets: list[tuple[ba.Widget, ba.Widget]] = [] for ach in self._achievements: a_complete = ach.complete imw = ba.imagewidget( parent=parent, draw_controller=btn, position=(xach, yach), size=(a_scale, a_scale), color=tuple(ach.get_icon_color(a_complete)[:3]) if a_complete else (1.2, 1.2, 1.2), texture=ach.get_icon_texture(a_complete)) imw2 = ba.imagewidget(parent=parent, draw_controller=btn, position=(xach, yach), size=(a_scale, a_scale), color=(2, 1.4, 0.4), texture=window.a_outline_tex, model_transparent=window.a_outline_model) self._achievement_widgets.append((imw, imw2)) # if a_complete: xach += a_scale * 1.2 # if not unlocked: self._lock_widget = ba.imagewidget(parent=parent, draw_controller=btn, position=(x - 8 + sclx * 0.5, y + scly * 0.5 - 20), size=(60, 60), opacity=0.0, texture=ba.gettexture('lock')) # give a quasi-random update increment to spread the load.. self._update_timer = ba.Timer(0.001 * (900 + random.randrange(200)), ba.WeakCall(self._update), repeat=True, timetype=ba.TimeType.REAL) self._update()
def _refresh(self) -> None: chars: Optional[List[str]] = None if self._mode in ['normal', 'caps']: chars = list(self._chars) if self._mode == 'caps': chars = [c.upper() for c in chars] ba.buttonwidget(edit=self._shift_button, color=self._key_color_lit if self._mode == 'caps' else self._key_color_dark, label=charstr(SpCh.SHIFT), on_activate_call=self._shift) ba.buttonwidget(edit=self._num_mode_button, label='123#&*', on_activate_call=self._num_mode) ba.buttonwidget(edit=self._emoji_button, color=self._key_color_dark, label=charstr(SpCh.LOGO_FLAT), on_activate_call=self._next_mode) else: if self._mode == 'num': chars = list(self._keyboard.nums) else: chars = list(self._keyboard.pages[self._mode]) ba.buttonwidget(edit=self._shift_button, color=self._key_color_dark, label='', on_activate_call=self._null_press) ba.buttonwidget(edit=self._num_mode_button, label='abc', on_activate_call=self._abc_mode) ba.buttonwidget(edit=self._emoji_button, color=self._key_color_dark, label=charstr(SpCh.LOGO_FLAT), on_activate_call=self._next_mode) for i, btn in enumerate(self._char_keys): assert chars is not None have_char = True if i >= len(chars): # No such char. have_char = False pagename = self._mode ba.print_error( f'Size of page "{pagename}" of keyboard' f' "{self._keyboard.name}" is incorrect:' f' {len(chars)} != {len(self._chars)}' f' (size of default "normal" page)', once=True) ba.buttonwidget(edit=btn, label=chars[i] if have_char else ' ', on_activate_call=ba.Call( self._type_char, chars[i] if have_char else ' '))
def __init__(self, origin: Sequence[float] = (0, 0)): _ba.set_party_window_open(True) self._r = 'partyWindow' self._popup_type: Optional[str] = None self._popup_party_member_client_id: Optional[int] = None self._popup_party_member_is_host: Optional[bool] = None self._width = 500 uiscale = ba.app.ui.uiscale self._height = (365 if uiscale is ba.UIScale.SMALL else 480 if uiscale is ba.UIScale.MEDIUM else 600) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', color=(0.40, 0.55, 0.20), parent=_ba.get_special_widget('overlay_stack'), on_outside_click_call=self.close_with_sound, scale_origin_stack_offset=origin, scale=(2.0 if uiscale is ba.UIScale.SMALL else 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=0.7, position=(30, self._height - 47), size=(50, 50), label='', on_activate_call=self.close, autoselect=True, color=(0.45, 0.63, 0.15), icon=ba.gettexture('crossOut'), iconscale=1.2) ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) self._menu_button = ba.buttonwidget( parent=self._root_widget, scale=0.7, position=(self._width - 60, self._height - 47), size=(50, 50), label='...', autoselect=True, button_type='square', on_activate_call=ba.WeakCall(self._on_menu_button_press), color=(0.55, 0.73, 0.25), iconscale=1.2) info = _ba.get_connection_to_host_info() if info.get('name', '') != '': title = ba.Lstr(value=info['name']) else: title = ba.Lstr(resource=self._r + '.titleText') self._title_text = ba.textwidget(parent=self._root_widget, scale=0.9, color=(0.5, 0.7, 0.5), text=title, size=(0, 0), position=(self._width * 0.5, self._height - 29), maxwidth=self._width * 0.7, h_align='center', v_align='center') self._empty_str = ba.textwidget(parent=self._root_widget, scale=0.75, size=(0, 0), position=(self._width * 0.5, self._height - 65), maxwidth=self._width * 0.85, h_align='center', v_align='center') self._scroll_width = self._width - 50 self._scrollwidget = ba.scrollwidget(parent=self._root_widget, size=(self._scroll_width, self._height - 200), position=(30, 80), color=(0.4, 0.6, 0.3)) self._columnwidget = ba.columnwidget(parent=self._scrollwidget, border=2, margin=0) ba.widget(edit=self._menu_button, down_widget=self._columnwidget) self._muted_text = ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.5), size=(0, 0), h_align='center', v_align='center', text=ba.Lstr(resource='chatMutedText')) self._chat_texts: List[ba.Widget] = [] # add all existing messages if chat is not muted if not ba.app.config.resolve('Chat Muted'): msgs = _ba.get_chat_messages() for msg in msgs: self._add_msg(msg) self._text_field = txt = ba.textwidget( parent=self._root_widget, editable=True, size=(530, 40), position=(44, 39), text='', maxwidth=494, shadow=0.3, flatness=1.0, description=ba.Lstr(resource=self._r + '.chatMessageText'), autoselect=True, v_align='center', corner_scale=0.7) ba.widget(edit=self._scrollwidget, autoselect=True, left_widget=self._cancel_button, up_widget=self._cancel_button, down_widget=self._text_field) ba.widget(edit=self._columnwidget, autoselect=True, up_widget=self._cancel_button, down_widget=self._text_field) ba.containerwidget(edit=self._root_widget, selected_child=txt) btn = ba.buttonwidget(parent=self._root_widget, size=(50, 35), label=ba.Lstr(resource=self._r + '.sendText'), button_type='square', autoselect=True, position=(self._width - 70, 35), on_activate_call=self._send_chat_message) ba.textwidget(edit=txt, on_return_press_call=btn.activate) self._name_widgets: List[ba.Widget] = [] self._roster: Optional[List[Dict[str, Any]]] = None self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), repeat=True, timetype=ba.TimeType.REAL) self._update()
def _load_keyboard(self) -> None: # pylint: disable=too-many-locals self._keyboard = self._get_keyboard() # We want to get just chars without column data, etc. self._chars = [j for i in self._keyboard.chars for j in i] self._modes = ['normal'] + list(self._keyboard.pages) self._mode_index = 0 self._mode = self._modes[self._mode_index] v = self._height - 180.0 key_width = 46 * 10 / len(self._keyboard.chars[0]) key_height = 46 * 3 / len(self._keyboard.chars) key_textcolor = (1, 1, 1) row_starts = (69.0, 95.0, 151.0) key_color = self._key_color key_color_dark = self._key_color_dark self._click_sound = ba.getsound('click01') # kill prev char keys for key in self._char_keys: key.delete() self._char_keys = [] # dummy data just used for row/column lengths... we don't actually # set things until refresh chars: List[Tuple[str, ...]] = self._keyboard.chars for row_num, row in enumerate(chars): h = row_starts[row_num] # shift key before row 3 if row_num == 2 and self._shift_button is None: self._shift_button = ba.buttonwidget( parent=self._root_widget, position=(h - key_width * 2.0, v), size=(key_width * 1.7, key_height), autoselect=True, textcolor=key_textcolor, color=key_color_dark, label=charstr(SpCh.SHIFT), enable_sound=False, extra_touch_border_scale=0.3, button_type='square', ) for _ in row: btn = ba.buttonwidget( parent=self._root_widget, position=(h, v), size=(key_width, key_height), autoselect=True, enable_sound=False, textcolor=key_textcolor, color=key_color, label='', button_type='square', extra_touch_border_scale=0.1, ) self._char_keys.append(btn) h += key_width + 10 # Add delete key at end of third row. if row_num == 2: if self._backspace_button is not None: self._backspace_button.delete() self._backspace_button = ba.buttonwidget( parent=self._root_widget, position=(h + 4, v), size=(key_width * 1.8, key_height), autoselect=True, enable_sound=False, repeat=True, textcolor=key_textcolor, color=key_color_dark, label=charstr(SpCh.DELETE), button_type='square', on_activate_call=self._del) v -= (key_height + 9) # Do space bar and stuff. if row_num == 2: if self._num_mode_button is None: self._num_mode_button = ba.buttonwidget( parent=self._root_widget, position=(112, v - 8), size=(key_width * 2, key_height + 5), enable_sound=False, button_type='square', extra_touch_border_scale=0.3, autoselect=True, textcolor=key_textcolor, color=key_color_dark, label='', ) if self._emoji_button is None: self._emoji_button = ba.buttonwidget( parent=self._root_widget, position=(56, v - 8), size=(key_width, key_height + 5), autoselect=True, enable_sound=False, textcolor=key_textcolor, color=key_color_dark, label=charstr(SpCh.LOGO_FLAT), extra_touch_border_scale=0.3, button_type='square', ) btn1 = self._num_mode_button if self._space_button is None: self._space_button = ba.buttonwidget( parent=self._root_widget, position=(210, v - 12), size=(key_width * 6.1, key_height + 15), extra_touch_border_scale=0.3, enable_sound=False, autoselect=True, textcolor=key_textcolor, color=key_color_dark, label=ba.Lstr(resource='spaceKeyText'), on_activate_call=ba.Call(self._type_char, ' ')) # Show change instructions only if we have more than one # keyboard option. if (ba.app.meta.metascan is not None and len(ba.app.meta.metascan.keyboards) > 1): ba.textwidget( parent=self._root_widget, h_align='center', position=(210, v - 70), size=(key_width * 6.1, key_height + 15), text=ba.Lstr( resource='keyboardChangeInstructionsText'), scale=0.75) btn2 = self._space_button btn3 = self._emoji_button ba.widget(edit=btn1, right_widget=btn2, left_widget=btn3) ba.widget(edit=btn2, left_widget=btn1, right_widget=self._done_button) ba.widget(edit=btn3, left_widget=btn1) ba.widget(edit=self._done_button, left_widget=btn2) ba.containerwidget(edit=self._root_widget, selected_child=self._char_keys[14]) self._refresh()
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 width = max(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.ui.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 _rebuild_ui(self) -> None: # pylint: disable=too-many-statements # pylint: disable=too-many-locals from ba.internal import get_device_value # Clear existing UI. for widget in self._root_widget.get_children(): widget.delete() self._textwidgets: Dict[str, ba.Widget] = {} # If we were supplied with settings, we're a secondary joystick and # just operate on that. in the other (normal) case we make our own. if not self._is_secondary: # Fill our temp config with present values (for our primary and # secondary controls). self._settings = {} for skey in [ 'buttonJump', 'buttonJump_B', 'buttonPunch', 'buttonPunch_B', 'buttonBomb', 'buttonBomb_B', 'buttonPickUp', 'buttonPickUp_B', 'buttonStart', 'buttonStart_B', 'buttonStart2', 'buttonStart2_B', 'buttonUp', 'buttonUp_B', 'buttonDown', 'buttonDown_B', 'buttonLeft', 'buttonLeft_B', 'buttonRight', 'buttonRight_B', 'buttonRun1', 'buttonRun1_B', 'buttonRun2', 'buttonRun2_B', 'triggerRun1', 'triggerRun1_B', 'triggerRun2', 'triggerRun2_B', 'buttonIgnored', 'buttonIgnored_B', 'buttonIgnored2', 'buttonIgnored2_B', 'buttonIgnored3', 'buttonIgnored3_B', 'buttonIgnored4', 'buttonIgnored4_B', 'buttonVRReorient', 'buttonVRReorient_B', 'analogStickDeadZone', 'analogStickDeadZone_B', 'dpad', 'dpad_B', 'unassignedButtonsRun', 'unassignedButtonsRun_B', 'startButtonActivatesDefaultWidget', 'startButtonActivatesDefaultWidget_B', 'uiOnly', 'uiOnly_B', 'ignoreCompletely', 'ignoreCompletely_B', 'autoRecalibrateAnalogStick', 'autoRecalibrateAnalogStick_B', 'analogStickLR', 'analogStickLR_B', 'analogStickUD', 'analogStickUD_B', 'enableSecondary', ]: val = get_device_value(self._input, skey) if val != -1: self._settings[skey] = val back_button: Optional[ba.Widget] if self._is_secondary: back_button = ba.buttonwidget(parent=self._root_widget, position=(self._width - 180, self._height - 65), autoselect=True, size=(160, 60), label=ba.Lstr(resource='doneText'), scale=0.9, on_activate_call=self._save) ba.containerwidget(edit=self._root_widget, start_button=back_button, on_cancel_call=back_button.activate) cancel_button = None else: cancel_button = ba.buttonwidget( parent=self._root_widget, position=(51, self._height - 65), autoselect=True, size=(160, 60), label=ba.Lstr(resource='cancelText'), scale=0.9, on_activate_call=self._cancel) ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button) save_button: Optional[ba.Widget] if not self._is_secondary: save_button = ba.buttonwidget( parent=self._root_widget, position=(self._width - (165 if self._is_secondary else 195), self._height - 65), size=((160 if self._is_secondary else 180), 60), autoselect=True, label=ba.Lstr(resource='doneText') if self._is_secondary else ba.Lstr(resource='saveText'), scale=0.9, on_activate_call=self._save) ba.containerwidget(edit=self._root_widget, start_button=save_button) else: save_button = None if not self._is_secondary: v = self._height - 59 ba.textwidget(parent=self._root_widget, position=(0, v + 5), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText'), color=ba.app.ui.title_color, maxwidth=310, h_align='center', v_align='center') v -= 48 ba.textwidget(parent=self._root_widget, position=(0, v + 3), size=(self._width, 25), text=self._name, color=ba.app.ui.infotextcolor, maxwidth=self._width * 0.9, h_align='center', v_align='center') v -= self._spacing * 1 ba.textwidget(parent=self._root_widget, position=(50, v + 10), size=(self._width - 100, 30), text=ba.Lstr(resource=self._r + '.appliesToAllText'), maxwidth=330, scale=0.65, color=(0.5, 0.6, 0.5, 1.0), h_align='center', v_align='center') v -= 70 self._enable_check_box = None else: v = self._height - 49 ba.textwidget(parent=self._root_widget, position=(0, v + 5), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.secondaryText'), color=ba.app.ui.title_color, maxwidth=300, h_align='center', v_align='center') v -= self._spacing * 1 ba.textwidget(parent=self._root_widget, position=(50, v + 10), size=(self._width - 100, 30), text=ba.Lstr(resource=self._r + '.secondHalfText'), maxwidth=300, scale=0.65, color=(0.6, 0.8, 0.6, 1.0), h_align='center') self._enable_check_box = ba.checkboxwidget( parent=self._root_widget, position=(self._width * 0.5 - 80, v - 73), value=self.get_enable_secondary_value(), autoselect=True, on_value_change_call=self._enable_check_box_changed, size=(200, 30), text=ba.Lstr(resource=self._r + '.secondaryEnableText'), scale=1.2) v = self._height - 205 h_offs = 160 dist = 70 d_color = (0.4, 0.4, 0.8) sclx = 1.2 scly = 0.98 dpm = ba.Lstr(resource=self._r + '.pressAnyButtonOrDpadText') dpm2 = ba.Lstr(resource=self._r + '.ifNothingHappensTryAnalogText') self._capture_button(pos=(h_offs, v + scly * dist), color=d_color, button='buttonUp' + self._ext, texture=ba.gettexture('upButton'), scale=1.0, message=dpm, message2=dpm2) self._capture_button(pos=(h_offs - sclx * dist, v), color=d_color, button='buttonLeft' + self._ext, texture=ba.gettexture('leftButton'), scale=1.0, message=dpm, message2=dpm2) self._capture_button(pos=(h_offs + sclx * dist, v), color=d_color, button='buttonRight' + self._ext, texture=ba.gettexture('rightButton'), scale=1.0, message=dpm, message2=dpm2) self._capture_button(pos=(h_offs, v - scly * dist), color=d_color, button='buttonDown' + self._ext, texture=ba.gettexture('downButton'), scale=1.0, message=dpm, message2=dpm2) dpm3 = ba.Lstr(resource=self._r + '.ifNothingHappensTryDpadText') self._capture_button(pos=(h_offs + 130, v - 125), color=(0.4, 0.4, 0.6), button='analogStickLR' + self._ext, maxwidth=140, texture=ba.gettexture('analogStick'), scale=1.2, message=ba.Lstr(resource=self._r + '.pressLeftRightText'), message2=dpm3) self._capture_button(pos=(self._width * 0.5, v), color=(0.4, 0.4, 0.6), button='buttonStart' + self._ext, texture=ba.gettexture('startButton'), scale=0.7) h_offs = self._width - 160 self._capture_button(pos=(h_offs, v + scly * dist), color=(0.6, 0.4, 0.8), button='buttonPickUp' + self._ext, texture=ba.gettexture('buttonPickUp'), scale=1.0) self._capture_button(pos=(h_offs - sclx * dist, v), color=(0.7, 0.5, 0.1), button='buttonPunch' + self._ext, texture=ba.gettexture('buttonPunch'), scale=1.0) self._capture_button(pos=(h_offs + sclx * dist, v), color=(0.5, 0.2, 0.1), button='buttonBomb' + self._ext, texture=ba.gettexture('buttonBomb'), scale=1.0) self._capture_button(pos=(h_offs, v - scly * dist), color=(0.2, 0.5, 0.2), button='buttonJump' + self._ext, texture=ba.gettexture('buttonJump'), scale=1.0) self._advanced_button = ba.buttonwidget( parent=self._root_widget, autoselect=True, label=ba.Lstr(resource=self._r + '.advancedText'), text_scale=0.9, color=(0.45, 0.4, 0.5), textcolor=(0.65, 0.6, 0.7), position=(self._width - 300, 30), size=(130, 40), on_activate_call=self._do_advanced) try: if cancel_button is not None and save_button is not None: ba.widget(edit=cancel_button, right_widget=save_button) ba.widget(edit=save_button, left_widget=cancel_button) except Exception: ba.print_exception('Error wiring up gamepad config window.')
def __init__(self, edit_profile_window: EditProfileWindow, transition: str = 'in_right'): from ba.internal import serverget self._r = 'editProfileWindow' self._width = 680 self._height = 350 self._base_scale = (2.05 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.2) self._upgrade_start_time: Optional[float] = None self._name = edit_profile_window.get_name() self._edit_profile_window = weakref.ref(edit_profile_window) top_extra = 15 if ba.app.small_ui else 15 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), toolbar_visibility='menu_currency', transition=transition, scale=self._base_scale, stack_offset=(0, 15) if ba.app.small_ui else (0, 0))) cancel_button = ba.buttonwidget(parent=self._root_widget, position=(52, 30), size=(155, 60), scale=0.8, autoselect=True, label=ba.Lstr(resource='cancelText'), on_activate_call=self._cancel) self._upgrade_button = ba.buttonwidget( parent=self._root_widget, position=(self._width - 190, 30), size=(155, 60), scale=0.8, autoselect=True, label=ba.Lstr(resource='upgradeText'), on_activate_call=self._on_upgrade_press) ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button, start_button=self._upgrade_button, selected_child=self._upgrade_button) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 38), size=(0, 0), text=ba.Lstr(resource=self._r + '.upgradeToGlobalProfileText'), color=ba.app.title_color, maxwidth=self._width * 0.45, scale=1.0, h_align="center", v_align="center") ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 100), size=(0, 0), text=ba.Lstr(resource=self._r + '.upgradeProfileInfoText'), color=ba.app.infotextcolor, maxwidth=self._width * 0.8, scale=0.7, h_align="center", v_align="center") self._status_text = ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 160), size=(0, 0), text=ba.Lstr(resource=self._r + '.checkingAvailabilityText', subs=[('${NAME}', self._name)]), color=(0.8, 0.4, 0.0), maxwidth=self._width * 0.8, scale=0.65, h_align="center", v_align="center") self._price_text = ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 230), size=(0, 0), text='', color=(0.2, 1, 0.2), maxwidth=self._width * 0.8, scale=1.5, h_align="center", v_align="center") self._tickets_text: Optional[ba.Widget] if not ba.app.toolbars: self._tickets_text = ba.textwidget( parent=self._root_widget, position=(self._width * 0.9 - 5, self._height - 30), size=(0, 0), text=ba.charstr(ba.SpecialChar.TICKET) + '123', color=(0.2, 1, 0.2), maxwidth=100, scale=0.5, h_align="right", v_align="center") else: self._tickets_text = None serverget('bsGlobalProfileCheck', { 'name': self._name, 'b': ba.app.build_number }, callback=ba.WeakCall(self._profile_check_result)) self._cost = _ba.get_account_misc_read_val('price.global_profile', 500) self._status: Optional[str] = 'waiting' 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 # 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()