bastd.ui.league.rankbutton
Provides a button showing league rank.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides a button showing league rank.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING 8 9import ba 10import ba.internal 11 12if TYPE_CHECKING: 13 from typing import Any, Callable 14 15 16class LeagueRankButton: 17 """Button showing league rank.""" 18 19 def __init__( 20 self, 21 parent: ba.Widget, 22 position: tuple[float, float], 23 size: tuple[float, float], 24 scale: float, 25 on_activate_call: Callable[[], Any] | None = None, 26 transition_delay: float | None = None, 27 color: tuple[float, float, float] | None = None, 28 textcolor: tuple[float, float, float] | None = None, 29 smooth_update_delay: float | None = None, 30 ): 31 if on_activate_call is None: 32 on_activate_call = ba.WeakCall(self._default_on_activate_call) 33 self._on_activate_call = on_activate_call 34 if smooth_update_delay is None: 35 smooth_update_delay = 1000 36 self._smooth_update_delay = smooth_update_delay 37 self._size = size 38 self._scale = scale 39 if color is None: 40 color = (0.5, 0.6, 0.5) 41 if textcolor is None: 42 textcolor = (1, 1, 1) 43 self._color = color 44 self._textcolor = textcolor 45 self._header_color = (0.8, 0.8, 2.0) 46 self._parent = parent 47 self._position: tuple[float, float] = (0.0, 0.0) 48 49 self._button = ba.buttonwidget( 50 parent=parent, 51 size=size, 52 label='', 53 button_type='square', 54 scale=scale, 55 autoselect=True, 56 on_activate_call=self._on_activate, 57 transition_delay=transition_delay, 58 color=color, 59 ) 60 61 self._title_text = ba.textwidget( 62 parent=parent, 63 size=(0, 0), 64 draw_controller=self._button, 65 h_align='center', 66 v_align='center', 67 maxwidth=size[0] * scale * 0.85, 68 text=ba.Lstr( 69 resource='league.leagueRankText', 70 fallback_resource='coopSelectWindow.powerRankingText', 71 ), 72 color=self._header_color, 73 flatness=1.0, 74 shadow=1.0, 75 scale=scale * 0.5, 76 transition_delay=transition_delay, 77 ) 78 79 self._value_text = ba.textwidget( 80 parent=parent, 81 size=(0, 0), 82 h_align='center', 83 v_align='center', 84 maxwidth=size[0] * scale * 0.85, 85 text='-', 86 draw_controller=self._button, 87 big=True, 88 scale=scale, 89 transition_delay=transition_delay, 90 color=textcolor, 91 ) 92 93 self._smooth_percent: float | None = None 94 self._percent: int | None = None 95 self._smooth_rank: float | None = None 96 self._rank: int | None = None 97 self._ticking_node: ba.Node | None = None 98 self._smooth_increase_speed = 1.0 99 self._league: str | None = None 100 self._improvement_text: str | None = None 101 102 self._smooth_update_timer: ba.Timer | None = None 103 104 # Take note of our account state; we'll refresh later if this changes. 105 self._account_state_num = ba.internal.get_v1_account_state_num() 106 self._last_power_ranking_query_time: float | None = None 107 self._doing_power_ranking_query = False 108 self.set_position(position) 109 self._bg_flash = False 110 self._update_timer = ba.Timer( 111 1.0, 112 ba.WeakCall(self._update), 113 timetype=ba.TimeType.REAL, 114 repeat=True, 115 ) 116 self._update() 117 118 # If we've got cached power-ranking data already, apply it. 119 data = ba.app.accounts_v1.get_cached_league_rank_data() 120 if data is not None: 121 self._update_for_league_rank_data(data) 122 123 def _on_activate(self) -> None: 124 ba.internal.increment_analytics_count('League rank button press') 125 self._on_activate_call() 126 127 def __del__(self) -> None: 128 if self._ticking_node is not None: 129 self._ticking_node.delete() 130 131 def _start_smooth_update(self) -> None: 132 self._smooth_update_timer = ba.Timer( 133 0.05, 134 ba.WeakCall(self._smooth_update), 135 repeat=True, 136 timetype=ba.TimeType.REAL, 137 ) 138 139 def _smooth_update(self) -> None: 140 # pylint: disable=too-many-branches 141 # pylint: disable=too-many-statements 142 try: 143 if not self._button: 144 return 145 if self._ticking_node is None: 146 with ba.Context('ui'): 147 self._ticking_node = ba.newnode( 148 'sound', 149 attrs={ 150 'sound': ba.getsound('scoreIncrease'), 151 'positional': False, 152 }, 153 ) 154 self._bg_flash = not self._bg_flash 155 color_used = ( 156 (self._color[0] * 2, self._color[1] * 2, self._color[2] * 2) 157 if self._bg_flash 158 else self._color 159 ) 160 textcolor_used = (1, 1, 1) if self._bg_flash else self._textcolor 161 header_color_used = ( 162 (1, 1, 1) if self._bg_flash else self._header_color 163 ) 164 165 if self._rank is not None: 166 assert self._smooth_rank is not None 167 self._smooth_rank -= 1.0 * self._smooth_increase_speed 168 finished = int(self._smooth_rank) <= self._rank 169 elif self._smooth_percent is not None: 170 self._smooth_percent += 1.0 * self._smooth_increase_speed 171 assert self._percent is not None 172 finished = int(self._smooth_percent) >= self._percent 173 else: 174 finished = True 175 if finished: 176 if self._rank is not None: 177 self._smooth_rank = float(self._rank) 178 elif self._percent is not None: 179 self._smooth_percent = float(self._percent) 180 color_used = self._color 181 textcolor_used = self._textcolor 182 self._smooth_update_timer = None 183 if self._ticking_node is not None: 184 self._ticking_node.delete() 185 self._ticking_node = None 186 ba.playsound(ba.getsound('cashRegister2')) 187 assert self._improvement_text is not None 188 diff_text = ba.textwidget( 189 parent=self._parent, 190 size=(0, 0), 191 h_align='center', 192 v_align='center', 193 text='+' + self._improvement_text + '!', 194 position=( 195 self._position[0] + self._size[0] * 0.5 * self._scale, 196 self._position[1] + self._size[1] * -0.2 * self._scale, 197 ), 198 color=(0, 1, 0), 199 flatness=1.0, 200 shadow=0.0, 201 scale=self._scale * 0.7, 202 ) 203 204 def safe_delete(widget: ba.Widget) -> None: 205 if widget: 206 widget.delete() 207 208 ba.timer( 209 2.0, 210 ba.Call(safe_delete, diff_text), 211 timetype=ba.TimeType.REAL, 212 ) 213 status_text: str | ba.Lstr 214 if self._rank is not None: 215 assert self._smooth_rank is not None 216 status_text = ba.Lstr( 217 resource='numberText', 218 subs=[('${NUMBER}', str(int(self._smooth_rank)))], 219 ) 220 elif self._smooth_percent is not None: 221 status_text = str(int(self._smooth_percent)) + '%' 222 else: 223 status_text = '-' 224 ba.textwidget( 225 edit=self._value_text, text=status_text, color=textcolor_used 226 ) 227 ba.textwidget(edit=self._title_text, color=header_color_used) 228 ba.buttonwidget(edit=self._button, color=color_used) 229 230 except Exception: 231 ba.print_exception('Error doing smooth update.') 232 self._smooth_update_timer = None 233 234 def _update_for_league_rank_data(self, data: dict[str, Any] | None) -> None: 235 # pylint: disable=too-many-branches 236 # pylint: disable=too-many-statements 237 238 # If our button has died, ignore. 239 if not self._button: 240 return 241 242 status_text: str | ba.Lstr 243 244 in_top = data is not None and data['rank'] is not None 245 do_percent = False 246 if data is None or ba.internal.get_v1_account_state() != 'signed_in': 247 self._percent = self._rank = None 248 status_text = '-' 249 elif in_top: 250 self._percent = None 251 self._rank = data['rank'] 252 prev_league = self._league 253 self._league = data['l'] 254 255 # If this is the first set, league has changed, or rank has gotten 256 # worse, snap the smooth value immediately. 257 assert self._rank is not None 258 if ( 259 self._smooth_rank is None 260 or prev_league != self._league 261 or self._rank > int(self._smooth_rank) 262 ): 263 self._smooth_rank = float(self._rank) 264 status_text = ba.Lstr( 265 resource='numberText', 266 subs=[('${NUMBER}', str(int(self._smooth_rank)))], 267 ) 268 else: 269 try: 270 if not data['scores'] or data['scores'][-1][1] <= 0: 271 self._percent = self._rank = None 272 status_text = '-' 273 else: 274 our_points = ba.app.accounts_v1.get_league_rank_points(data) 275 progress = float(our_points) / data['scores'][-1][1] 276 self._percent = int(progress * 100.0) 277 self._rank = None 278 do_percent = True 279 prev_league = self._league 280 self._league = data['l'] 281 282 # If this is the first set, league has changed, or percent 283 # has decreased, snap the smooth value immediately. 284 if ( 285 self._smooth_percent is None 286 or prev_league != self._league 287 or self._percent < int(self._smooth_percent) 288 ): 289 self._smooth_percent = float(self._percent) 290 status_text = str(int(self._smooth_percent)) + '%' 291 292 except Exception: 293 ba.print_exception('Error updating power ranking.') 294 self._percent = self._rank = None 295 status_text = '-' 296 297 # If we're doing a smooth update, set a timer. 298 if ( 299 self._rank is not None 300 and self._smooth_rank is not None 301 and int(self._smooth_rank) != self._rank 302 ): 303 self._improvement_text = str( 304 -(int(self._rank) - int(self._smooth_rank)) 305 ) 306 diff = abs(self._rank - self._smooth_rank) 307 if diff > 100: 308 self._smooth_increase_speed = diff / 80.0 309 elif diff > 50: 310 self._smooth_increase_speed = diff / 70.0 311 elif diff > 25: 312 self._smooth_increase_speed = diff / 55.0 313 else: 314 self._smooth_increase_speed = diff / 40.0 315 self._smooth_increase_speed = max(0.4, self._smooth_increase_speed) 316 ba.timer( 317 self._smooth_update_delay, 318 ba.WeakCall(self._start_smooth_update), 319 timetype=ba.TimeType.REAL, 320 timeformat=ba.TimeFormat.MILLISECONDS, 321 ) 322 323 if ( 324 self._percent is not None 325 and self._smooth_percent is not None 326 and int(self._smooth_percent) != self._percent 327 ): 328 self._improvement_text = str( 329 (int(self._percent) - int(self._smooth_percent)) 330 ) 331 self._smooth_increase_speed = 0.3 332 ba.timer( 333 self._smooth_update_delay, 334 ba.WeakCall(self._start_smooth_update), 335 timetype=ba.TimeType.REAL, 336 timeformat=ba.TimeFormat.MILLISECONDS, 337 ) 338 339 if do_percent: 340 ba.textwidget( 341 edit=self._title_text, 342 text=ba.Lstr(resource='coopSelectWindow.toRankedText'), 343 ) 344 else: 345 try: 346 assert data is not None 347 txt = ba.Lstr( 348 resource='league.leagueFullText', 349 subs=[ 350 ( 351 '${NAME}', 352 ba.Lstr(translate=('leagueNames', data['l']['n'])), 353 ), 354 ], 355 ) 356 t_color = data['l']['c'] 357 except Exception: 358 txt = ba.Lstr( 359 resource='league.leagueRankText', 360 fallback_resource='coopSelectWindow.powerRankingText', 361 ) 362 t_color = ba.app.ui.title_color 363 ba.textwidget(edit=self._title_text, text=txt, color=t_color) 364 ba.textwidget(edit=self._value_text, text=status_text) 365 366 def _on_power_ranking_query_response( 367 self, data: dict[str, Any] | None 368 ) -> None: 369 self._doing_power_ranking_query = False 370 ba.app.accounts_v1.cache_league_rank_data(data) 371 self._update_for_league_rank_data(data) 372 373 def _update(self) -> None: 374 cur_time = ba.time(ba.TimeType.REAL) 375 376 # If our account state has changed, refresh our UI. 377 account_state_num = ba.internal.get_v1_account_state_num() 378 if account_state_num != self._account_state_num: 379 self._account_state_num = account_state_num 380 381 # And power ranking too... 382 if not self._doing_power_ranking_query: 383 self._last_power_ranking_query_time = None 384 385 # Send off a new power-ranking query if its been 386 # long enough or whatnot. 387 if not self._doing_power_ranking_query and ( 388 self._last_power_ranking_query_time is None 389 or cur_time - self._last_power_ranking_query_time > 30.0 390 ): 391 self._last_power_ranking_query_time = cur_time 392 self._doing_power_ranking_query = True 393 ba.internal.power_ranking_query( 394 callback=ba.WeakCall(self._on_power_ranking_query_response) 395 ) 396 397 def _default_on_activate_call(self) -> None: 398 # pylint: disable=cyclic-import 399 from bastd.ui.league.rankwindow import LeagueRankWindow 400 401 LeagueRankWindow(modal=True, origin_widget=self._button) 402 403 def set_position(self, position: tuple[float, float]) -> None: 404 """Set the button's position.""" 405 self._position = position 406 if not self._button: 407 return 408 ba.buttonwidget(edit=self._button, position=self._position) 409 ba.textwidget( 410 edit=self._title_text, 411 position=( 412 self._position[0] + self._size[0] * 0.5 * self._scale, 413 self._position[1] + self._size[1] * 0.82 * self._scale, 414 ), 415 ) 416 ba.textwidget( 417 edit=self._value_text, 418 position=( 419 self._position[0] + self._size[0] * 0.5 * self._scale, 420 self._position[1] + self._size[1] * 0.36 * self._scale, 421 ), 422 ) 423 424 def get_button(self) -> ba.Widget: 425 """Return the underlying button ba.Widget>""" 426 return self._button
class
LeagueRankButton:
17class LeagueRankButton: 18 """Button showing league rank.""" 19 20 def __init__( 21 self, 22 parent: ba.Widget, 23 position: tuple[float, float], 24 size: tuple[float, float], 25 scale: float, 26 on_activate_call: Callable[[], Any] | None = None, 27 transition_delay: float | None = None, 28 color: tuple[float, float, float] | None = None, 29 textcolor: tuple[float, float, float] | None = None, 30 smooth_update_delay: float | None = None, 31 ): 32 if on_activate_call is None: 33 on_activate_call = ba.WeakCall(self._default_on_activate_call) 34 self._on_activate_call = on_activate_call 35 if smooth_update_delay is None: 36 smooth_update_delay = 1000 37 self._smooth_update_delay = smooth_update_delay 38 self._size = size 39 self._scale = scale 40 if color is None: 41 color = (0.5, 0.6, 0.5) 42 if textcolor is None: 43 textcolor = (1, 1, 1) 44 self._color = color 45 self._textcolor = textcolor 46 self._header_color = (0.8, 0.8, 2.0) 47 self._parent = parent 48 self._position: tuple[float, float] = (0.0, 0.0) 49 50 self._button = ba.buttonwidget( 51 parent=parent, 52 size=size, 53 label='', 54 button_type='square', 55 scale=scale, 56 autoselect=True, 57 on_activate_call=self._on_activate, 58 transition_delay=transition_delay, 59 color=color, 60 ) 61 62 self._title_text = ba.textwidget( 63 parent=parent, 64 size=(0, 0), 65 draw_controller=self._button, 66 h_align='center', 67 v_align='center', 68 maxwidth=size[0] * scale * 0.85, 69 text=ba.Lstr( 70 resource='league.leagueRankText', 71 fallback_resource='coopSelectWindow.powerRankingText', 72 ), 73 color=self._header_color, 74 flatness=1.0, 75 shadow=1.0, 76 scale=scale * 0.5, 77 transition_delay=transition_delay, 78 ) 79 80 self._value_text = ba.textwidget( 81 parent=parent, 82 size=(0, 0), 83 h_align='center', 84 v_align='center', 85 maxwidth=size[0] * scale * 0.85, 86 text='-', 87 draw_controller=self._button, 88 big=True, 89 scale=scale, 90 transition_delay=transition_delay, 91 color=textcolor, 92 ) 93 94 self._smooth_percent: float | None = None 95 self._percent: int | None = None 96 self._smooth_rank: float | None = None 97 self._rank: int | None = None 98 self._ticking_node: ba.Node | None = None 99 self._smooth_increase_speed = 1.0 100 self._league: str | None = None 101 self._improvement_text: str | None = None 102 103 self._smooth_update_timer: ba.Timer | None = None 104 105 # Take note of our account state; we'll refresh later if this changes. 106 self._account_state_num = ba.internal.get_v1_account_state_num() 107 self._last_power_ranking_query_time: float | None = None 108 self._doing_power_ranking_query = False 109 self.set_position(position) 110 self._bg_flash = False 111 self._update_timer = ba.Timer( 112 1.0, 113 ba.WeakCall(self._update), 114 timetype=ba.TimeType.REAL, 115 repeat=True, 116 ) 117 self._update() 118 119 # If we've got cached power-ranking data already, apply it. 120 data = ba.app.accounts_v1.get_cached_league_rank_data() 121 if data is not None: 122 self._update_for_league_rank_data(data) 123 124 def _on_activate(self) -> None: 125 ba.internal.increment_analytics_count('League rank button press') 126 self._on_activate_call() 127 128 def __del__(self) -> None: 129 if self._ticking_node is not None: 130 self._ticking_node.delete() 131 132 def _start_smooth_update(self) -> None: 133 self._smooth_update_timer = ba.Timer( 134 0.05, 135 ba.WeakCall(self._smooth_update), 136 repeat=True, 137 timetype=ba.TimeType.REAL, 138 ) 139 140 def _smooth_update(self) -> None: 141 # pylint: disable=too-many-branches 142 # pylint: disable=too-many-statements 143 try: 144 if not self._button: 145 return 146 if self._ticking_node is None: 147 with ba.Context('ui'): 148 self._ticking_node = ba.newnode( 149 'sound', 150 attrs={ 151 'sound': ba.getsound('scoreIncrease'), 152 'positional': False, 153 }, 154 ) 155 self._bg_flash = not self._bg_flash 156 color_used = ( 157 (self._color[0] * 2, self._color[1] * 2, self._color[2] * 2) 158 if self._bg_flash 159 else self._color 160 ) 161 textcolor_used = (1, 1, 1) if self._bg_flash else self._textcolor 162 header_color_used = ( 163 (1, 1, 1) if self._bg_flash else self._header_color 164 ) 165 166 if self._rank is not None: 167 assert self._smooth_rank is not None 168 self._smooth_rank -= 1.0 * self._smooth_increase_speed 169 finished = int(self._smooth_rank) <= self._rank 170 elif self._smooth_percent is not None: 171 self._smooth_percent += 1.0 * self._smooth_increase_speed 172 assert self._percent is not None 173 finished = int(self._smooth_percent) >= self._percent 174 else: 175 finished = True 176 if finished: 177 if self._rank is not None: 178 self._smooth_rank = float(self._rank) 179 elif self._percent is not None: 180 self._smooth_percent = float(self._percent) 181 color_used = self._color 182 textcolor_used = self._textcolor 183 self._smooth_update_timer = None 184 if self._ticking_node is not None: 185 self._ticking_node.delete() 186 self._ticking_node = None 187 ba.playsound(ba.getsound('cashRegister2')) 188 assert self._improvement_text is not None 189 diff_text = ba.textwidget( 190 parent=self._parent, 191 size=(0, 0), 192 h_align='center', 193 v_align='center', 194 text='+' + self._improvement_text + '!', 195 position=( 196 self._position[0] + self._size[0] * 0.5 * self._scale, 197 self._position[1] + self._size[1] * -0.2 * self._scale, 198 ), 199 color=(0, 1, 0), 200 flatness=1.0, 201 shadow=0.0, 202 scale=self._scale * 0.7, 203 ) 204 205 def safe_delete(widget: ba.Widget) -> None: 206 if widget: 207 widget.delete() 208 209 ba.timer( 210 2.0, 211 ba.Call(safe_delete, diff_text), 212 timetype=ba.TimeType.REAL, 213 ) 214 status_text: str | ba.Lstr 215 if self._rank is not None: 216 assert self._smooth_rank is not None 217 status_text = ba.Lstr( 218 resource='numberText', 219 subs=[('${NUMBER}', str(int(self._smooth_rank)))], 220 ) 221 elif self._smooth_percent is not None: 222 status_text = str(int(self._smooth_percent)) + '%' 223 else: 224 status_text = '-' 225 ba.textwidget( 226 edit=self._value_text, text=status_text, color=textcolor_used 227 ) 228 ba.textwidget(edit=self._title_text, color=header_color_used) 229 ba.buttonwidget(edit=self._button, color=color_used) 230 231 except Exception: 232 ba.print_exception('Error doing smooth update.') 233 self._smooth_update_timer = None 234 235 def _update_for_league_rank_data(self, data: dict[str, Any] | None) -> None: 236 # pylint: disable=too-many-branches 237 # pylint: disable=too-many-statements 238 239 # If our button has died, ignore. 240 if not self._button: 241 return 242 243 status_text: str | ba.Lstr 244 245 in_top = data is not None and data['rank'] is not None 246 do_percent = False 247 if data is None or ba.internal.get_v1_account_state() != 'signed_in': 248 self._percent = self._rank = None 249 status_text = '-' 250 elif in_top: 251 self._percent = None 252 self._rank = data['rank'] 253 prev_league = self._league 254 self._league = data['l'] 255 256 # If this is the first set, league has changed, or rank has gotten 257 # worse, snap the smooth value immediately. 258 assert self._rank is not None 259 if ( 260 self._smooth_rank is None 261 or prev_league != self._league 262 or self._rank > int(self._smooth_rank) 263 ): 264 self._smooth_rank = float(self._rank) 265 status_text = ba.Lstr( 266 resource='numberText', 267 subs=[('${NUMBER}', str(int(self._smooth_rank)))], 268 ) 269 else: 270 try: 271 if not data['scores'] or data['scores'][-1][1] <= 0: 272 self._percent = self._rank = None 273 status_text = '-' 274 else: 275 our_points = ba.app.accounts_v1.get_league_rank_points(data) 276 progress = float(our_points) / data['scores'][-1][1] 277 self._percent = int(progress * 100.0) 278 self._rank = None 279 do_percent = True 280 prev_league = self._league 281 self._league = data['l'] 282 283 # If this is the first set, league has changed, or percent 284 # has decreased, snap the smooth value immediately. 285 if ( 286 self._smooth_percent is None 287 or prev_league != self._league 288 or self._percent < int(self._smooth_percent) 289 ): 290 self._smooth_percent = float(self._percent) 291 status_text = str(int(self._smooth_percent)) + '%' 292 293 except Exception: 294 ba.print_exception('Error updating power ranking.') 295 self._percent = self._rank = None 296 status_text = '-' 297 298 # If we're doing a smooth update, set a timer. 299 if ( 300 self._rank is not None 301 and self._smooth_rank is not None 302 and int(self._smooth_rank) != self._rank 303 ): 304 self._improvement_text = str( 305 -(int(self._rank) - int(self._smooth_rank)) 306 ) 307 diff = abs(self._rank - self._smooth_rank) 308 if diff > 100: 309 self._smooth_increase_speed = diff / 80.0 310 elif diff > 50: 311 self._smooth_increase_speed = diff / 70.0 312 elif diff > 25: 313 self._smooth_increase_speed = diff / 55.0 314 else: 315 self._smooth_increase_speed = diff / 40.0 316 self._smooth_increase_speed = max(0.4, self._smooth_increase_speed) 317 ba.timer( 318 self._smooth_update_delay, 319 ba.WeakCall(self._start_smooth_update), 320 timetype=ba.TimeType.REAL, 321 timeformat=ba.TimeFormat.MILLISECONDS, 322 ) 323 324 if ( 325 self._percent is not None 326 and self._smooth_percent is not None 327 and int(self._smooth_percent) != self._percent 328 ): 329 self._improvement_text = str( 330 (int(self._percent) - int(self._smooth_percent)) 331 ) 332 self._smooth_increase_speed = 0.3 333 ba.timer( 334 self._smooth_update_delay, 335 ba.WeakCall(self._start_smooth_update), 336 timetype=ba.TimeType.REAL, 337 timeformat=ba.TimeFormat.MILLISECONDS, 338 ) 339 340 if do_percent: 341 ba.textwidget( 342 edit=self._title_text, 343 text=ba.Lstr(resource='coopSelectWindow.toRankedText'), 344 ) 345 else: 346 try: 347 assert data is not None 348 txt = ba.Lstr( 349 resource='league.leagueFullText', 350 subs=[ 351 ( 352 '${NAME}', 353 ba.Lstr(translate=('leagueNames', data['l']['n'])), 354 ), 355 ], 356 ) 357 t_color = data['l']['c'] 358 except Exception: 359 txt = ba.Lstr( 360 resource='league.leagueRankText', 361 fallback_resource='coopSelectWindow.powerRankingText', 362 ) 363 t_color = ba.app.ui.title_color 364 ba.textwidget(edit=self._title_text, text=txt, color=t_color) 365 ba.textwidget(edit=self._value_text, text=status_text) 366 367 def _on_power_ranking_query_response( 368 self, data: dict[str, Any] | None 369 ) -> None: 370 self._doing_power_ranking_query = False 371 ba.app.accounts_v1.cache_league_rank_data(data) 372 self._update_for_league_rank_data(data) 373 374 def _update(self) -> None: 375 cur_time = ba.time(ba.TimeType.REAL) 376 377 # If our account state has changed, refresh our UI. 378 account_state_num = ba.internal.get_v1_account_state_num() 379 if account_state_num != self._account_state_num: 380 self._account_state_num = account_state_num 381 382 # And power ranking too... 383 if not self._doing_power_ranking_query: 384 self._last_power_ranking_query_time = None 385 386 # Send off a new power-ranking query if its been 387 # long enough or whatnot. 388 if not self._doing_power_ranking_query and ( 389 self._last_power_ranking_query_time is None 390 or cur_time - self._last_power_ranking_query_time > 30.0 391 ): 392 self._last_power_ranking_query_time = cur_time 393 self._doing_power_ranking_query = True 394 ba.internal.power_ranking_query( 395 callback=ba.WeakCall(self._on_power_ranking_query_response) 396 ) 397 398 def _default_on_activate_call(self) -> None: 399 # pylint: disable=cyclic-import 400 from bastd.ui.league.rankwindow import LeagueRankWindow 401 402 LeagueRankWindow(modal=True, origin_widget=self._button) 403 404 def set_position(self, position: tuple[float, float]) -> None: 405 """Set the button's position.""" 406 self._position = position 407 if not self._button: 408 return 409 ba.buttonwidget(edit=self._button, position=self._position) 410 ba.textwidget( 411 edit=self._title_text, 412 position=( 413 self._position[0] + self._size[0] * 0.5 * self._scale, 414 self._position[1] + self._size[1] * 0.82 * self._scale, 415 ), 416 ) 417 ba.textwidget( 418 edit=self._value_text, 419 position=( 420 self._position[0] + self._size[0] * 0.5 * self._scale, 421 self._position[1] + self._size[1] * 0.36 * self._scale, 422 ), 423 ) 424 425 def get_button(self) -> ba.Widget: 426 """Return the underlying button ba.Widget>""" 427 return self._button
Button showing league rank.
LeagueRankButton( parent: _ba.Widget, position: tuple[float, float], size: tuple[float, float], scale: float, on_activate_call: Optional[Callable[[], Any]] = None, transition_delay: float | None = None, color: tuple[float, float, float] | None = None, textcolor: tuple[float, float, float] | None = None, smooth_update_delay: float | None = None)
20 def __init__( 21 self, 22 parent: ba.Widget, 23 position: tuple[float, float], 24 size: tuple[float, float], 25 scale: float, 26 on_activate_call: Callable[[], Any] | None = None, 27 transition_delay: float | None = None, 28 color: tuple[float, float, float] | None = None, 29 textcolor: tuple[float, float, float] | None = None, 30 smooth_update_delay: float | None = None, 31 ): 32 if on_activate_call is None: 33 on_activate_call = ba.WeakCall(self._default_on_activate_call) 34 self._on_activate_call = on_activate_call 35 if smooth_update_delay is None: 36 smooth_update_delay = 1000 37 self._smooth_update_delay = smooth_update_delay 38 self._size = size 39 self._scale = scale 40 if color is None: 41 color = (0.5, 0.6, 0.5) 42 if textcolor is None: 43 textcolor = (1, 1, 1) 44 self._color = color 45 self._textcolor = textcolor 46 self._header_color = (0.8, 0.8, 2.0) 47 self._parent = parent 48 self._position: tuple[float, float] = (0.0, 0.0) 49 50 self._button = ba.buttonwidget( 51 parent=parent, 52 size=size, 53 label='', 54 button_type='square', 55 scale=scale, 56 autoselect=True, 57 on_activate_call=self._on_activate, 58 transition_delay=transition_delay, 59 color=color, 60 ) 61 62 self._title_text = ba.textwidget( 63 parent=parent, 64 size=(0, 0), 65 draw_controller=self._button, 66 h_align='center', 67 v_align='center', 68 maxwidth=size[0] * scale * 0.85, 69 text=ba.Lstr( 70 resource='league.leagueRankText', 71 fallback_resource='coopSelectWindow.powerRankingText', 72 ), 73 color=self._header_color, 74 flatness=1.0, 75 shadow=1.0, 76 scale=scale * 0.5, 77 transition_delay=transition_delay, 78 ) 79 80 self._value_text = ba.textwidget( 81 parent=parent, 82 size=(0, 0), 83 h_align='center', 84 v_align='center', 85 maxwidth=size[0] * scale * 0.85, 86 text='-', 87 draw_controller=self._button, 88 big=True, 89 scale=scale, 90 transition_delay=transition_delay, 91 color=textcolor, 92 ) 93 94 self._smooth_percent: float | None = None 95 self._percent: int | None = None 96 self._smooth_rank: float | None = None 97 self._rank: int | None = None 98 self._ticking_node: ba.Node | None = None 99 self._smooth_increase_speed = 1.0 100 self._league: str | None = None 101 self._improvement_text: str | None = None 102 103 self._smooth_update_timer: ba.Timer | None = None 104 105 # Take note of our account state; we'll refresh later if this changes. 106 self._account_state_num = ba.internal.get_v1_account_state_num() 107 self._last_power_ranking_query_time: float | None = None 108 self._doing_power_ranking_query = False 109 self.set_position(position) 110 self._bg_flash = False 111 self._update_timer = ba.Timer( 112 1.0, 113 ba.WeakCall(self._update), 114 timetype=ba.TimeType.REAL, 115 repeat=True, 116 ) 117 self._update() 118 119 # If we've got cached power-ranking data already, apply it. 120 data = ba.app.accounts_v1.get_cached_league_rank_data() 121 if data is not None: 122 self._update_for_league_rank_data(data)
def
set_position(self, position: tuple[float, float]) -> None:
404 def set_position(self, position: tuple[float, float]) -> None: 405 """Set the button's position.""" 406 self._position = position 407 if not self._button: 408 return 409 ba.buttonwidget(edit=self._button, position=self._position) 410 ba.textwidget( 411 edit=self._title_text, 412 position=( 413 self._position[0] + self._size[0] * 0.5 * self._scale, 414 self._position[1] + self._size[1] * 0.82 * self._scale, 415 ), 416 ) 417 ba.textwidget( 418 edit=self._value_text, 419 position=( 420 self._position[0] + self._size[0] * 0.5 * self._scale, 421 self._position[1] + self._size[1] * 0.36 * self._scale, 422 ), 423 )
Set the button's position.