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