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 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 50 if uiscale is bui.UIScale.MEDIUM 51 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 60 if uiscale is bui.UIScale.MEDIUM 61 else 450 62 ) 63 64 bg_color = (0.5, 0.4, 0.6) 65 66 # creates our _root_widget 67 super().__init__( 68 position=position, 69 size=(self._width, self._height), 70 scale=scale, 71 bg_color=bg_color, 72 offset=offset, 73 ) 74 75 self._cancel_button = bui.buttonwidget( 76 parent=self.root_widget, 77 position=(50, self._height - 30), 78 size=(50, 50), 79 scale=0.5, 80 label='', 81 color=bg_color, 82 on_activate_call=self._on_cancel_press, 83 autoselect=True, 84 icon=bui.gettexture('crossOut'), 85 iconscale=1.2, 86 ) 87 88 self._title_text = bui.textwidget( 89 parent=self.root_widget, 90 position=(self._width * 0.5, self._height - 20), 91 size=(0, 0), 92 h_align='center', 93 v_align='center', 94 scale=0.6, 95 text=bui.Lstr(resource='tournamentStandingsText'), 96 maxwidth=200, 97 color=(1, 1, 1, 0.4), 98 ) 99 100 self._scrollwidget = bui.scrollwidget( 101 parent=self.root_widget, 102 size=(self._width - 60, self._height - 70), 103 position=(30, 30), 104 highlight=False, 105 simple_culling_v=10, 106 ) 107 bui.widget(edit=self._scrollwidget, autoselect=True) 108 109 self._loading_text = bui.textwidget( 110 parent=self._scrollwidget, 111 scale=0.5, 112 text=bui.Lstr( 113 value='${A}...', 114 subs=[('${A}', bui.Lstr(resource='loadingText'))], 115 ), 116 size=(self._width - 60, 100), 117 h_align='center', 118 v_align='center', 119 ) 120 121 bui.containerwidget( 122 edit=self.root_widget, cancel_button=self._cancel_button 123 ) 124 125 plus.tournament_query( 126 args={ 127 'tournamentIDs': [tournament_id], 128 'numScores': 50, 129 'source': 'scores window', 130 }, 131 callback=bui.WeakCall(self._on_tournament_query_response), 132 ) 133 134 def _on_tournament_query_response( 135 self, data: dict[str, Any] | None 136 ) -> None: 137 if data is not None: 138 # this used to be the whole payload 139 data_t: list[dict[str, Any]] = data['t'] 140 # kill our loading text if we've got scores.. otherwise just 141 # replace it with 'no scores yet' 142 if data_t[0]['scores']: 143 self._loading_text.delete() 144 else: 145 bui.textwidget( 146 edit=self._loading_text, 147 text=bui.Lstr(resource='noScoresYetText'), 148 ) 149 incr = 30 150 sub_width = self._width - 90 151 sub_height = 30 + len(data_t[0]['scores']) * incr 152 self._subcontainer = bui.containerwidget( 153 parent=self._scrollwidget, 154 size=(sub_width, sub_height), 155 background=False, 156 ) 157 for i, entry in enumerate(data_t[0]['scores']): 158 bui.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 bui.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 bui.timestring( 182 (entry[0] * 10) / 1000.0, 183 centi=True, 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 = bui.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=bui.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 bui.textwidget( 214 edit=txt, 215 on_activate_call=bui.Call( 216 self._show_player_info, entry, txt 217 ), 218 ) 219 if i == 0: 220 bui.widget(edit=txt, up_widget=self._cancel_button) 221 222 def _show_player_info(self, entry: Any, textwidget: bui.Widget) -> None: 223 from bauiv1lib.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 bui.getsound('error').play() 228 return 229 bui.getsound('swish').play() 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 bui.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 bui.getsound('swish').play() 249 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 51 if uiscale is bui.UIScale.MEDIUM 52 else 1.23 53 ) 54 self._transitioning_out = False 55 56 self._width = 400 57 self._height = ( 58 300 59 if uiscale is bui.UIScale.SMALL 60 else 370 61 if uiscale is bui.UIScale.MEDIUM 62 else 450 63 ) 64 65 bg_color = (0.5, 0.4, 0.6) 66 67 # creates our _root_widget 68 super().__init__( 69 position=position, 70 size=(self._width, self._height), 71 scale=scale, 72 bg_color=bg_color, 73 offset=offset, 74 ) 75 76 self._cancel_button = bui.buttonwidget( 77 parent=self.root_widget, 78 position=(50, self._height - 30), 79 size=(50, 50), 80 scale=0.5, 81 label='', 82 color=bg_color, 83 on_activate_call=self._on_cancel_press, 84 autoselect=True, 85 icon=bui.gettexture('crossOut'), 86 iconscale=1.2, 87 ) 88 89 self._title_text = bui.textwidget( 90 parent=self.root_widget, 91 position=(self._width * 0.5, self._height - 20), 92 size=(0, 0), 93 h_align='center', 94 v_align='center', 95 scale=0.6, 96 text=bui.Lstr(resource='tournamentStandingsText'), 97 maxwidth=200, 98 color=(1, 1, 1, 0.4), 99 ) 100 101 self._scrollwidget = bui.scrollwidget( 102 parent=self.root_widget, 103 size=(self._width - 60, self._height - 70), 104 position=(30, 30), 105 highlight=False, 106 simple_culling_v=10, 107 ) 108 bui.widget(edit=self._scrollwidget, autoselect=True) 109 110 self._loading_text = bui.textwidget( 111 parent=self._scrollwidget, 112 scale=0.5, 113 text=bui.Lstr( 114 value='${A}...', 115 subs=[('${A}', bui.Lstr(resource='loadingText'))], 116 ), 117 size=(self._width - 60, 100), 118 h_align='center', 119 v_align='center', 120 ) 121 122 bui.containerwidget( 123 edit=self.root_widget, cancel_button=self._cancel_button 124 ) 125 126 plus.tournament_query( 127 args={ 128 'tournamentIDs': [tournament_id], 129 'numScores': 50, 130 'source': 'scores window', 131 }, 132 callback=bui.WeakCall(self._on_tournament_query_response), 133 ) 134 135 def _on_tournament_query_response( 136 self, data: dict[str, Any] | None 137 ) -> None: 138 if data is not None: 139 # this used to be the whole payload 140 data_t: list[dict[str, Any]] = data['t'] 141 # kill our loading text if we've got scores.. otherwise just 142 # replace it with 'no scores yet' 143 if data_t[0]['scores']: 144 self._loading_text.delete() 145 else: 146 bui.textwidget( 147 edit=self._loading_text, 148 text=bui.Lstr(resource='noScoresYetText'), 149 ) 150 incr = 30 151 sub_width = self._width - 90 152 sub_height = 30 + len(data_t[0]['scores']) * incr 153 self._subcontainer = bui.containerwidget( 154 parent=self._scrollwidget, 155 size=(sub_width, sub_height), 156 background=False, 157 ) 158 for i, entry in enumerate(data_t[0]['scores']): 159 bui.textwidget( 160 parent=self._subcontainer, 161 position=(sub_width * 0.1 - 5, sub_height - 20 - incr * i), 162 maxwidth=20, 163 scale=0.5, 164 color=(0.6, 0.6, 0.7), 165 flatness=1.0, 166 shadow=0.0, 167 text=str(i + 1), 168 size=(0, 0), 169 h_align='right', 170 v_align='center', 171 ) 172 173 bui.textwidget( 174 parent=self._subcontainer, 175 position=(sub_width * 0.25 - 2, sub_height - 20 - incr * i), 176 maxwidth=sub_width * 0.24, 177 color=(0.9, 1.0, 0.9), 178 flatness=1.0, 179 shadow=0.0, 180 scale=0.6, 181 text=( 182 bui.timestring( 183 (entry[0] * 10) / 1000.0, 184 centi=True, 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 = bui.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=bui.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 bui.textwidget( 215 edit=txt, 216 on_activate_call=bui.Call( 217 self._show_player_info, entry, txt 218 ), 219 ) 220 if i == 0: 221 bui.widget(edit=txt, up_widget=self._cancel_button) 222 223 def _show_player_info(self, entry: Any, textwidget: bui.Widget) -> None: 224 from bauiv1lib.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 bui.getsound('error').play() 229 return 230 bui.getsound('swish').play() 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 bui.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 bui.getsound('swish').play() 250 self._transition_out()
Window for viewing tournament scores.
TournamentScoresWindow( tournament_id: str, tournament_activity: bascenev1._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)
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 51 if uiscale is bui.UIScale.MEDIUM 52 else 1.23 53 ) 54 self._transitioning_out = False 55 56 self._width = 400 57 self._height = ( 58 300 59 if uiscale is bui.UIScale.SMALL 60 else 370 61 if uiscale is bui.UIScale.MEDIUM 62 else 450 63 ) 64 65 bg_color = (0.5, 0.4, 0.6) 66 67 # creates our _root_widget 68 super().__init__( 69 position=position, 70 size=(self._width, self._height), 71 scale=scale, 72 bg_color=bg_color, 73 offset=offset, 74 ) 75 76 self._cancel_button = bui.buttonwidget( 77 parent=self.root_widget, 78 position=(50, self._height - 30), 79 size=(50, 50), 80 scale=0.5, 81 label='', 82 color=bg_color, 83 on_activate_call=self._on_cancel_press, 84 autoselect=True, 85 icon=bui.gettexture('crossOut'), 86 iconscale=1.2, 87 ) 88 89 self._title_text = bui.textwidget( 90 parent=self.root_widget, 91 position=(self._width * 0.5, self._height - 20), 92 size=(0, 0), 93 h_align='center', 94 v_align='center', 95 scale=0.6, 96 text=bui.Lstr(resource='tournamentStandingsText'), 97 maxwidth=200, 98 color=(1, 1, 1, 0.4), 99 ) 100 101 self._scrollwidget = bui.scrollwidget( 102 parent=self.root_widget, 103 size=(self._width - 60, self._height - 70), 104 position=(30, 30), 105 highlight=False, 106 simple_culling_v=10, 107 ) 108 bui.widget(edit=self._scrollwidget, autoselect=True) 109 110 self._loading_text = bui.textwidget( 111 parent=self._scrollwidget, 112 scale=0.5, 113 text=bui.Lstr( 114 value='${A}...', 115 subs=[('${A}', bui.Lstr(resource='loadingText'))], 116 ), 117 size=(self._width - 60, 100), 118 h_align='center', 119 v_align='center', 120 ) 121 122 bui.containerwidget( 123 edit=self.root_widget, cancel_button=self._cancel_button 124 ) 125 126 plus.tournament_query( 127 args={ 128 'tournamentIDs': [tournament_id], 129 'numScores': 50, 130 'source': 'scores window', 131 }, 132 callback=bui.WeakCall(self._on_tournament_query_response), 133 )
def
on_popup_cancel(self) -> None:
Called when the popup is canceled.
Cancels can occur due to clicking outside the window, hitting escape, etc.