bastd.ui.tournamentscores
Provides a popup for viewing tournament scores.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a popup for viewing tournament scores.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING 8 9import ba 10import ba.internal 11from bastd.ui import popup as popup_ui 12 13if TYPE_CHECKING: 14 from typing import Any, Sequence, Callable 15 16 17class TournamentScoresWindow(popup_ui.PopupWindow): 18 """Window for viewing tournament scores.""" 19 20 def __init__( 21 self, 22 tournament_id: str, 23 tournament_activity: ba.GameActivity | None = None, 24 position: tuple[float, float] = (0.0, 0.0), 25 scale: float | None = None, 26 offset: tuple[float, float] = (0.0, 0.0), 27 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 28 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 29 selected_character: str | None = None, 30 on_close_call: Callable[[], Any] | None = None, 31 ): 32 33 del tournament_activity # unused arg 34 del tint_color # unused arg 35 del tint2_color # unused arg 36 del selected_character # unused arg 37 self._tournament_id = tournament_id 38 self._subcontainer: ba.Widget | None = None 39 self._on_close_call = on_close_call 40 uiscale = ba.app.ui.uiscale 41 if scale is None: 42 scale = ( 43 2.3 44 if uiscale is ba.UIScale.SMALL 45 else 1.65 46 if uiscale is ba.UIScale.MEDIUM 47 else 1.23 48 ) 49 self._transitioning_out = False 50 51 self._width = 400 52 self._height = ( 53 300 54 if uiscale is ba.UIScale.SMALL 55 else 370 56 if uiscale is ba.UIScale.MEDIUM 57 else 450 58 ) 59 60 bg_color = (0.5, 0.4, 0.6) 61 62 # creates our _root_widget 63 super().__init__( 64 position=position, 65 size=(self._width, self._height), 66 scale=scale, 67 bg_color=bg_color, 68 offset=offset, 69 ) 70 71 # app = ba.app 72 73 self._cancel_button = ba.buttonwidget( 74 parent=self.root_widget, 75 position=(50, self._height - 30), 76 size=(50, 50), 77 scale=0.5, 78 label='', 79 color=bg_color, 80 on_activate_call=self._on_cancel_press, 81 autoselect=True, 82 icon=ba.gettexture('crossOut'), 83 iconscale=1.2, 84 ) 85 86 self._title_text = ba.textwidget( 87 parent=self.root_widget, 88 position=(self._width * 0.5, self._height - 20), 89 size=(0, 0), 90 h_align='center', 91 v_align='center', 92 scale=0.6, 93 text=ba.Lstr(resource='tournamentStandingsText'), 94 maxwidth=200, 95 color=(1, 1, 1, 0.4), 96 ) 97 98 self._scrollwidget = ba.scrollwidget( 99 parent=self.root_widget, 100 size=(self._width - 60, self._height - 70), 101 position=(30, 30), 102 highlight=False, 103 simple_culling_v=10, 104 ) 105 ba.widget(edit=self._scrollwidget, autoselect=True) 106 107 self._loading_text = ba.textwidget( 108 parent=self._scrollwidget, 109 scale=0.5, 110 text=ba.Lstr( 111 value='${A}...', 112 subs=[('${A}', ba.Lstr(resource='loadingText'))], 113 ), 114 size=(self._width - 60, 100), 115 h_align='center', 116 v_align='center', 117 ) 118 119 ba.containerwidget( 120 edit=self.root_widget, cancel_button=self._cancel_button 121 ) 122 123 ba.internal.tournament_query( 124 args={ 125 'tournamentIDs': [tournament_id], 126 'numScores': 50, 127 'source': 'scores window', 128 }, 129 callback=ba.WeakCall(self._on_tournament_query_response), 130 ) 131 132 def _on_tournament_query_response( 133 self, data: dict[str, Any] | None 134 ) -> None: 135 if data is not None: 136 # this used to be the whole payload 137 data_t: list[dict[str, Any]] = data['t'] 138 # kill our loading text if we've got scores.. otherwise just 139 # replace it with 'no scores yet' 140 if data_t[0]['scores']: 141 self._loading_text.delete() 142 else: 143 ba.textwidget( 144 edit=self._loading_text, 145 text=ba.Lstr(resource='noScoresYetText'), 146 ) 147 incr = 30 148 sub_width = self._width - 90 149 sub_height = 30 + len(data_t[0]['scores']) * incr 150 self._subcontainer = ba.containerwidget( 151 parent=self._scrollwidget, 152 size=(sub_width, sub_height), 153 background=False, 154 ) 155 for i, entry in enumerate(data_t[0]['scores']): 156 157 ba.textwidget( 158 parent=self._subcontainer, 159 position=(sub_width * 0.1 - 5, sub_height - 20 - incr * i), 160 maxwidth=20, 161 scale=0.5, 162 color=(0.6, 0.6, 0.7), 163 flatness=1.0, 164 shadow=0.0, 165 text=str(i + 1), 166 size=(0, 0), 167 h_align='right', 168 v_align='center', 169 ) 170 171 ba.textwidget( 172 parent=self._subcontainer, 173 position=(sub_width * 0.25 - 2, sub_height - 20 - incr * i), 174 maxwidth=sub_width * 0.24, 175 color=(0.9, 1.0, 0.9), 176 flatness=1.0, 177 shadow=0.0, 178 scale=0.6, 179 text=( 180 ba.timestring( 181 entry[0] * 10, 182 centi=True, 183 timeformat=ba.TimeFormat.MILLISECONDS, 184 ) 185 if data_t[0]['scoreType'] == 'time' 186 else str(entry[0]) 187 ), 188 size=(0, 0), 189 h_align='center', 190 v_align='center', 191 ) 192 193 txt = ba.textwidget( 194 parent=self._subcontainer, 195 position=( 196 sub_width * 0.25, 197 sub_height - 20 - incr * i - (0.5 / 0.7) * incr, 198 ), 199 maxwidth=sub_width * 0.6, 200 scale=0.7, 201 flatness=1.0, 202 shadow=0.0, 203 text=ba.Lstr(value=entry[1]), 204 selectable=True, 205 click_activate=True, 206 autoselect=True, 207 extra_touch_border_scale=0.0, 208 size=((sub_width * 0.6) / 0.7, incr / 0.7), 209 h_align='left', 210 v_align='center', 211 ) 212 213 ba.textwidget( 214 edit=txt, 215 on_activate_call=ba.Call( 216 self._show_player_info, entry, txt 217 ), 218 ) 219 if i == 0: 220 ba.widget(edit=txt, up_widget=self._cancel_button) 221 222 def _show_player_info(self, entry: Any, textwidget: ba.Widget) -> None: 223 from bastd.ui.account.viewer import AccountViewerWindow 224 225 # for the moment we only work if a single player-info is present.. 226 if len(entry[2]) != 1: 227 ba.playsound(ba.getsound('error')) 228 return 229 ba.playsound(ba.getsound('swish')) 230 AccountViewerWindow( 231 account_id=entry[2][0].get('a', None), 232 profile_id=entry[2][0].get('p', None), 233 position=textwidget.get_screen_space_center(), 234 ) 235 self._transition_out() 236 237 def _on_cancel_press(self) -> None: 238 self._transition_out() 239 240 def _transition_out(self) -> None: 241 if not self._transitioning_out: 242 self._transitioning_out = True 243 ba.containerwidget(edit=self.root_widget, transition='out_scale') 244 if self._on_close_call is not None: 245 self._on_close_call() 246 247 def on_popup_cancel(self) -> None: 248 ba.playsound(ba.getsound('swish')) 249 self._transition_out()
18class TournamentScoresWindow(popup_ui.PopupWindow): 19 """Window for viewing tournament scores.""" 20 21 def __init__( 22 self, 23 tournament_id: str, 24 tournament_activity: ba.GameActivity | None = None, 25 position: tuple[float, float] = (0.0, 0.0), 26 scale: float | None = None, 27 offset: tuple[float, float] = (0.0, 0.0), 28 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 29 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 30 selected_character: str | None = None, 31 on_close_call: Callable[[], Any] | None = None, 32 ): 33 34 del tournament_activity # unused arg 35 del tint_color # unused arg 36 del tint2_color # unused arg 37 del selected_character # unused arg 38 self._tournament_id = tournament_id 39 self._subcontainer: ba.Widget | None = None 40 self._on_close_call = on_close_call 41 uiscale = ba.app.ui.uiscale 42 if scale is None: 43 scale = ( 44 2.3 45 if uiscale is ba.UIScale.SMALL 46 else 1.65 47 if uiscale is ba.UIScale.MEDIUM 48 else 1.23 49 ) 50 self._transitioning_out = False 51 52 self._width = 400 53 self._height = ( 54 300 55 if uiscale is ba.UIScale.SMALL 56 else 370 57 if uiscale is ba.UIScale.MEDIUM 58 else 450 59 ) 60 61 bg_color = (0.5, 0.4, 0.6) 62 63 # creates our _root_widget 64 super().__init__( 65 position=position, 66 size=(self._width, self._height), 67 scale=scale, 68 bg_color=bg_color, 69 offset=offset, 70 ) 71 72 # app = ba.app 73 74 self._cancel_button = ba.buttonwidget( 75 parent=self.root_widget, 76 position=(50, self._height - 30), 77 size=(50, 50), 78 scale=0.5, 79 label='', 80 color=bg_color, 81 on_activate_call=self._on_cancel_press, 82 autoselect=True, 83 icon=ba.gettexture('crossOut'), 84 iconscale=1.2, 85 ) 86 87 self._title_text = ba.textwidget( 88 parent=self.root_widget, 89 position=(self._width * 0.5, self._height - 20), 90 size=(0, 0), 91 h_align='center', 92 v_align='center', 93 scale=0.6, 94 text=ba.Lstr(resource='tournamentStandingsText'), 95 maxwidth=200, 96 color=(1, 1, 1, 0.4), 97 ) 98 99 self._scrollwidget = ba.scrollwidget( 100 parent=self.root_widget, 101 size=(self._width - 60, self._height - 70), 102 position=(30, 30), 103 highlight=False, 104 simple_culling_v=10, 105 ) 106 ba.widget(edit=self._scrollwidget, autoselect=True) 107 108 self._loading_text = ba.textwidget( 109 parent=self._scrollwidget, 110 scale=0.5, 111 text=ba.Lstr( 112 value='${A}...', 113 subs=[('${A}', ba.Lstr(resource='loadingText'))], 114 ), 115 size=(self._width - 60, 100), 116 h_align='center', 117 v_align='center', 118 ) 119 120 ba.containerwidget( 121 edit=self.root_widget, cancel_button=self._cancel_button 122 ) 123 124 ba.internal.tournament_query( 125 args={ 126 'tournamentIDs': [tournament_id], 127 'numScores': 50, 128 'source': 'scores window', 129 }, 130 callback=ba.WeakCall(self._on_tournament_query_response), 131 ) 132 133 def _on_tournament_query_response( 134 self, data: dict[str, Any] | None 135 ) -> None: 136 if data is not None: 137 # this used to be the whole payload 138 data_t: list[dict[str, Any]] = data['t'] 139 # kill our loading text if we've got scores.. otherwise just 140 # replace it with 'no scores yet' 141 if data_t[0]['scores']: 142 self._loading_text.delete() 143 else: 144 ba.textwidget( 145 edit=self._loading_text, 146 text=ba.Lstr(resource='noScoresYetText'), 147 ) 148 incr = 30 149 sub_width = self._width - 90 150 sub_height = 30 + len(data_t[0]['scores']) * incr 151 self._subcontainer = ba.containerwidget( 152 parent=self._scrollwidget, 153 size=(sub_width, sub_height), 154 background=False, 155 ) 156 for i, entry in enumerate(data_t[0]['scores']): 157 158 ba.textwidget( 159 parent=self._subcontainer, 160 position=(sub_width * 0.1 - 5, sub_height - 20 - incr * i), 161 maxwidth=20, 162 scale=0.5, 163 color=(0.6, 0.6, 0.7), 164 flatness=1.0, 165 shadow=0.0, 166 text=str(i + 1), 167 size=(0, 0), 168 h_align='right', 169 v_align='center', 170 ) 171 172 ba.textwidget( 173 parent=self._subcontainer, 174 position=(sub_width * 0.25 - 2, sub_height - 20 - incr * i), 175 maxwidth=sub_width * 0.24, 176 color=(0.9, 1.0, 0.9), 177 flatness=1.0, 178 shadow=0.0, 179 scale=0.6, 180 text=( 181 ba.timestring( 182 entry[0] * 10, 183 centi=True, 184 timeformat=ba.TimeFormat.MILLISECONDS, 185 ) 186 if data_t[0]['scoreType'] == 'time' 187 else str(entry[0]) 188 ), 189 size=(0, 0), 190 h_align='center', 191 v_align='center', 192 ) 193 194 txt = ba.textwidget( 195 parent=self._subcontainer, 196 position=( 197 sub_width * 0.25, 198 sub_height - 20 - incr * i - (0.5 / 0.7) * incr, 199 ), 200 maxwidth=sub_width * 0.6, 201 scale=0.7, 202 flatness=1.0, 203 shadow=0.0, 204 text=ba.Lstr(value=entry[1]), 205 selectable=True, 206 click_activate=True, 207 autoselect=True, 208 extra_touch_border_scale=0.0, 209 size=((sub_width * 0.6) / 0.7, incr / 0.7), 210 h_align='left', 211 v_align='center', 212 ) 213 214 ba.textwidget( 215 edit=txt, 216 on_activate_call=ba.Call( 217 self._show_player_info, entry, txt 218 ), 219 ) 220 if i == 0: 221 ba.widget(edit=txt, up_widget=self._cancel_button) 222 223 def _show_player_info(self, entry: Any, textwidget: ba.Widget) -> None: 224 from bastd.ui.account.viewer import AccountViewerWindow 225 226 # for the moment we only work if a single player-info is present.. 227 if len(entry[2]) != 1: 228 ba.playsound(ba.getsound('error')) 229 return 230 ba.playsound(ba.getsound('swish')) 231 AccountViewerWindow( 232 account_id=entry[2][0].get('a', None), 233 profile_id=entry[2][0].get('p', None), 234 position=textwidget.get_screen_space_center(), 235 ) 236 self._transition_out() 237 238 def _on_cancel_press(self) -> None: 239 self._transition_out() 240 241 def _transition_out(self) -> None: 242 if not self._transitioning_out: 243 self._transitioning_out = True 244 ba.containerwidget(edit=self.root_widget, transition='out_scale') 245 if self._on_close_call is not None: 246 self._on_close_call() 247 248 def on_popup_cancel(self) -> None: 249 ba.playsound(ba.getsound('swish')) 250 self._transition_out()
Window for viewing tournament scores.
TournamentScoresWindow( tournament_id: str, tournament_activity: ba._gameactivity.GameActivity | None = None, position: tuple[float, float] = (0.0, 0.0), scale: float | None = 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_character: str | None = None, on_close_call: Optional[Callable[[], Any]] = None)
21 def __init__( 22 self, 23 tournament_id: str, 24 tournament_activity: ba.GameActivity | None = None, 25 position: tuple[float, float] = (0.0, 0.0), 26 scale: float | None = None, 27 offset: tuple[float, float] = (0.0, 0.0), 28 tint_color: Sequence[float] = (1.0, 1.0, 1.0), 29 tint2_color: Sequence[float] = (1.0, 1.0, 1.0), 30 selected_character: str | None = None, 31 on_close_call: Callable[[], Any] | None = None, 32 ): 33 34 del tournament_activity # unused arg 35 del tint_color # unused arg 36 del tint2_color # unused arg 37 del selected_character # unused arg 38 self._tournament_id = tournament_id 39 self._subcontainer: ba.Widget | None = None 40 self._on_close_call = on_close_call 41 uiscale = ba.app.ui.uiscale 42 if scale is None: 43 scale = ( 44 2.3 45 if uiscale is ba.UIScale.SMALL 46 else 1.65 47 if uiscale is ba.UIScale.MEDIUM 48 else 1.23 49 ) 50 self._transitioning_out = False 51 52 self._width = 400 53 self._height = ( 54 300 55 if uiscale is ba.UIScale.SMALL 56 else 370 57 if uiscale is ba.UIScale.MEDIUM 58 else 450 59 ) 60 61 bg_color = (0.5, 0.4, 0.6) 62 63 # creates our _root_widget 64 super().__init__( 65 position=position, 66 size=(self._width, self._height), 67 scale=scale, 68 bg_color=bg_color, 69 offset=offset, 70 ) 71 72 # app = ba.app 73 74 self._cancel_button = ba.buttonwidget( 75 parent=self.root_widget, 76 position=(50, self._height - 30), 77 size=(50, 50), 78 scale=0.5, 79 label='', 80 color=bg_color, 81 on_activate_call=self._on_cancel_press, 82 autoselect=True, 83 icon=ba.gettexture('crossOut'), 84 iconscale=1.2, 85 ) 86 87 self._title_text = ba.textwidget( 88 parent=self.root_widget, 89 position=(self._width * 0.5, self._height - 20), 90 size=(0, 0), 91 h_align='center', 92 v_align='center', 93 scale=0.6, 94 text=ba.Lstr(resource='tournamentStandingsText'), 95 maxwidth=200, 96 color=(1, 1, 1, 0.4), 97 ) 98 99 self._scrollwidget = ba.scrollwidget( 100 parent=self.root_widget, 101 size=(self._width - 60, self._height - 70), 102 position=(30, 30), 103 highlight=False, 104 simple_culling_v=10, 105 ) 106 ba.widget(edit=self._scrollwidget, autoselect=True) 107 108 self._loading_text = ba.textwidget( 109 parent=self._scrollwidget, 110 scale=0.5, 111 text=ba.Lstr( 112 value='${A}...', 113 subs=[('${A}', ba.Lstr(resource='loadingText'))], 114 ), 115 size=(self._width - 60, 100), 116 h_align='center', 117 v_align='center', 118 ) 119 120 ba.containerwidget( 121 edit=self.root_widget, cancel_button=self._cancel_button 122 ) 123 124 ba.internal.tournament_query( 125 args={ 126 'tournamentIDs': [tournament_id], 127 'numScores': 50, 128 'source': 'scores window', 129 }, 130 callback=ba.WeakCall(self._on_tournament_query_response), 131 )