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