bauiv1lib.coop.tournamentbutton

Defines button for co-op games.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines button for co-op games."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8import copy
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    from typing import Any, Callable
 14
 15
 16class TournamentButton:
 17    """Button showing a tournament in coop window."""
 18
 19    def __init__(
 20        self,
 21        parent: bui.Widget,
 22        x: float,
 23        y: float,
 24        select: bool,
 25        on_pressed: Callable[[TournamentButton], None],
 26    ) -> None:
 27        self._r = 'coopSelectWindow'
 28        sclx = 300
 29        scly = 195.0
 30        self.on_pressed = on_pressed
 31        self.lsbt = bui.getmesh('level_select_button_transparent')
 32        self.lsbo = bui.getmesh('level_select_button_opaque')
 33        self.allow_ads = False
 34        self.tournament_id: str | None = None
 35        self.time_remaining: int = 0
 36        self.has_time_remaining: bool = False
 37        self.leader: Any = None
 38        self.required_league: str | None = None
 39        self.button = btn = bui.buttonwidget(
 40            parent=parent,
 41            position=(x + 23, y + 4),
 42            size=(sclx, scly),
 43            label='',
 44            button_type='square',
 45            autoselect=True,
 46            on_activate_call=bui.WeakCall(self._pressed),
 47        )
 48        bui.widget(
 49            edit=btn,
 50            show_buffer_bottom=50,
 51            show_buffer_top=50,
 52            show_buffer_left=400,
 53            show_buffer_right=200,
 54        )
 55        if select:
 56            bui.containerwidget(
 57                edit=parent, selected_child=btn, visible_child=btn
 58            )
 59        image_width = sclx * 0.85 * 0.75
 60
 61        self.image = bui.imagewidget(
 62            parent=parent,
 63            draw_controller=btn,
 64            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
 65            size=(image_width, image_width * 0.5),
 66            mesh_transparent=self.lsbt,
 67            mesh_opaque=self.lsbo,
 68            texture=bui.gettexture('black'),
 69            opacity=0.2,
 70            mask_texture=bui.gettexture('mapPreviewMask'),
 71        )
 72
 73        self.lock_image = bui.imagewidget(
 74            parent=parent,
 75            draw_controller=btn,
 76            position=(x + 21 + sclx * 0.5 - image_width * 0.25, y + scly - 150),
 77            size=(image_width * 0.5, image_width * 0.5),
 78            texture=bui.gettexture('lock'),
 79            opacity=0.0,
 80        )
 81
 82        self.button_text = bui.textwidget(
 83            parent=parent,
 84            draw_controller=btn,
 85            position=(x + 20 + sclx * 0.5, y + scly - 35),
 86            size=(0, 0),
 87            h_align='center',
 88            text='-',
 89            v_align='center',
 90            maxwidth=sclx * 0.76,
 91            scale=0.85,
 92            color=(0.8, 1.0, 0.8, 1.0),
 93        )
 94
 95        header_color = (0.43, 0.4, 0.5, 1)
 96        value_color = (0.6, 0.6, 0.6, 1)
 97
 98        x_offs = 0
 99        bui.textwidget(
100            parent=parent,
101            draw_controller=btn,
102            position=(x + 360, y + scly - 20),
103            size=(0, 0),
104            h_align='center',
105            text=bui.Lstr(resource=self._r + '.entryFeeText'),
106            v_align='center',
107            maxwidth=100,
108            scale=0.9,
109            color=header_color,
110            flatness=1.0,
111        )
112
113        self.entry_fee_text_top = bui.textwidget(
114            parent=parent,
115            draw_controller=btn,
116            position=(x + 360, y + scly - 60),
117            size=(0, 0),
118            h_align='center',
119            text='-',
120            v_align='center',
121            maxwidth=60,
122            scale=1.3,
123            color=value_color,
124            flatness=1.0,
125        )
126        self.entry_fee_text_or = bui.textwidget(
127            parent=parent,
128            draw_controller=btn,
129            position=(x + 360, y + scly - 90),
130            size=(0, 0),
131            h_align='center',
132            text='',
133            v_align='center',
134            maxwidth=60,
135            scale=0.5,
136            color=value_color,
137            flatness=1.0,
138        )
139        self.entry_fee_text_remaining = bui.textwidget(
140            parent=parent,
141            draw_controller=btn,
142            position=(x + 360, y + scly - 90),
143            size=(0, 0),
144            h_align='center',
145            text='',
146            v_align='center',
147            maxwidth=60,
148            scale=0.5,
149            color=value_color,
150            flatness=1.0,
151        )
152
153        self.entry_fee_ad_image = bui.imagewidget(
154            parent=parent,
155            size=(40, 40),
156            draw_controller=btn,
157            position=(x + 360 - 20, y + scly - 140),
158            opacity=0.0,
159            texture=bui.gettexture('tv'),
160        )
161
162        x_offs += 50
163
164        bui.textwidget(
165            parent=parent,
166            draw_controller=btn,
167            position=(x + 447 + x_offs, y + scly - 20),
168            size=(0, 0),
169            h_align='center',
170            text=bui.Lstr(resource=self._r + '.prizesText'),
171            v_align='center',
172            maxwidth=130,
173            scale=0.9,
174            color=header_color,
175            flatness=1.0,
176        )
177
178        self.button_x = x
179        self.button_y = y
180        self.button_scale_y = scly
181
182        xo2 = 0
183        prize_value_scale = 1.5
184
185        self.prize_range_1_text = bui.textwidget(
186            parent=parent,
187            draw_controller=btn,
188            position=(x + 355 + xo2 + x_offs, y + scly - 93),
189            size=(0, 0),
190            h_align='right',
191            v_align='center',
192            maxwidth=50,
193            text='-',
194            scale=0.8,
195            color=header_color,
196            flatness=1.0,
197        )
198        self.prize_value_1_text = bui.textwidget(
199            parent=parent,
200            draw_controller=btn,
201            position=(x + 380 + xo2 + x_offs, y + scly - 93),
202            size=(0, 0),
203            h_align='left',
204            text='-',
205            v_align='center',
206            maxwidth=100,
207            scale=prize_value_scale,
208            color=value_color,
209            flatness=1.0,
210        )
211
212        self.prize_range_2_text = bui.textwidget(
213            parent=parent,
214            draw_controller=btn,
215            position=(x + 355 + xo2 + x_offs, y + scly - 93),
216            size=(0, 0),
217            h_align='right',
218            v_align='center',
219            maxwidth=50,
220            scale=0.8,
221            color=header_color,
222            flatness=1.0,
223        )
224        self.prize_value_2_text = bui.textwidget(
225            parent=parent,
226            draw_controller=btn,
227            position=(x + 380 + xo2 + x_offs, y + scly - 93),
228            size=(0, 0),
229            h_align='left',
230            text='',
231            v_align='center',
232            maxwidth=100,
233            scale=prize_value_scale,
234            color=value_color,
235            flatness=1.0,
236        )
237
238        self.prize_range_3_text = bui.textwidget(
239            parent=parent,
240            draw_controller=btn,
241            position=(x + 355 + xo2 + x_offs, y + scly - 93),
242            size=(0, 0),
243            h_align='right',
244            v_align='center',
245            maxwidth=50,
246            scale=0.8,
247            color=header_color,
248            flatness=1.0,
249        )
250        self.prize_value_3_text = bui.textwidget(
251            parent=parent,
252            draw_controller=btn,
253            position=(x + 380 + xo2 + x_offs, y + scly - 93),
254            size=(0, 0),
255            h_align='left',
256            text='',
257            v_align='center',
258            maxwidth=100,
259            scale=prize_value_scale,
260            color=value_color,
261            flatness=1.0,
262        )
263
264        bui.textwidget(
265            parent=parent,
266            draw_controller=btn,
267            position=(x + 620 + x_offs, y + scly - 20),
268            size=(0, 0),
269            h_align='center',
270            text=bui.Lstr(resource=self._r + '.currentBestText'),
271            v_align='center',
272            maxwidth=180,
273            scale=0.9,
274            color=header_color,
275            flatness=1.0,
276        )
277        self.current_leader_name_text = bui.textwidget(
278            parent=parent,
279            draw_controller=btn,
280            position=(
281                x + 620 + x_offs - (170 / 1.4) * 0.5,
282                y + scly - 60 - 40 * 0.5,
283            ),
284            selectable=True,
285            click_activate=True,
286            autoselect=True,
287            on_activate_call=bui.WeakCall(self._show_leader),
288            size=(170 / 1.4, 40),
289            h_align='center',
290            text='-',
291            v_align='center',
292            maxwidth=170,
293            scale=1.4,
294            color=value_color,
295            flatness=1.0,
296        )
297        self.current_leader_score_text = bui.textwidget(
298            parent=parent,
299            draw_controller=btn,
300            position=(x + 620 + x_offs, y + scly - 113 + 10),
301            size=(0, 0),
302            h_align='center',
303            text='-',
304            v_align='center',
305            maxwidth=170,
306            scale=1.8,
307            color=value_color,
308            flatness=1.0,
309        )
310
311        self.more_scores_button = bui.buttonwidget(
312            parent=parent,
313            position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
314            color=(0.5, 0.5, 0.6),
315            textcolor=(0.7, 0.7, 0.8),
316            label='-',
317            size=(120, 40),
318            autoselect=True,
319            up_widget=self.current_leader_name_text,
320            text_scale=0.6,
321            on_activate_call=bui.WeakCall(self._show_scores),
322        )
323        bui.widget(
324            edit=self.current_leader_name_text,
325            down_widget=self.more_scores_button,
326        )
327
328        bui.textwidget(
329            parent=parent,
330            draw_controller=btn,
331            position=(x + 820 + x_offs, y + scly - 20),
332            size=(0, 0),
333            h_align='center',
334            text=bui.Lstr(resource=self._r + '.timeRemainingText'),
335            v_align='center',
336            maxwidth=180,
337            scale=0.9,
338            color=header_color,
339            flatness=1.0,
340        )
341        self.time_remaining_value_text = bui.textwidget(
342            parent=parent,
343            draw_controller=btn,
344            position=(x + 820 + x_offs, y + scly - 68),
345            size=(0, 0),
346            h_align='center',
347            text='-',
348            v_align='center',
349            maxwidth=180,
350            scale=2.0,
351            color=value_color,
352            flatness=1.0,
353        )
354        self.time_remaining_out_of_text = bui.textwidget(
355            parent=parent,
356            draw_controller=btn,
357            position=(x + 820 + x_offs, y + scly - 110),
358            size=(0, 0),
359            h_align='center',
360            text='-',
361            v_align='center',
362            maxwidth=120,
363            scale=0.72,
364            color=(0.4, 0.4, 0.5),
365            flatness=1.0,
366        )
367
368    def _pressed(self) -> None:
369        self.on_pressed(self)
370
371    def _show_leader(self) -> None:
372        # pylint: disable=cyclic-import
373        from bauiv1lib.account.viewer import AccountViewerWindow
374
375        tournament_id = self.tournament_id
376
377        # FIXME: This assumes a single player entry in leader; should expand
378        #  this to work with multiple.
379        if (
380            tournament_id is None
381            or self.leader is None
382            or len(self.leader[2]) != 1
383        ):
384            bui.getsound('error').play()
385            return
386        bui.getsound('swish').play()
387        AccountViewerWindow(
388            account_id=self.leader[2][0].get('a', None),
389            profile_id=self.leader[2][0].get('p', None),
390            position=self.current_leader_name_text.get_screen_space_center(),
391        )
392
393    def _show_scores(self) -> None:
394        # pylint: disable=cyclic-import
395        from bauiv1lib.tournamentscores import TournamentScoresWindow
396
397        tournament_id = self.tournament_id
398        if tournament_id is None:
399            bui.getsound('error').play()
400            return
401
402        TournamentScoresWindow(
403            tournament_id=tournament_id,
404            position=self.more_scores_button.get_screen_space_center(),
405        )
406
407    def update_for_data(self, entry: dict[str, Any]) -> None:
408        """Update for new incoming data."""
409        # pylint: disable=too-many-statements
410        # pylint: disable=too-many-locals
411        # pylint: disable=too-many-branches
412
413        plus = bui.app.plus
414        assert plus is not None
415
416        assert bui.app.classic is not None
417        prize_y_offs = (
418            34
419            if 'prizeRange3' in entry
420            else 20 if 'prizeRange2' in entry else 12
421        )
422        x_offs = 90
423
424        # pylint: disable=useless-suppression
425        # pylint: disable=unbalanced-tuple-unpacking
426        (
427            pr1,
428            pv1,
429            pr2,
430            pv2,
431            pr3,
432            pv3,
433        ) = bui.app.classic.get_tournament_prize_strings(entry)
434        # pylint: enable=unbalanced-tuple-unpacking
435        # pylint: enable=useless-suppression
436
437        enabled = 'requiredLeague' not in entry
438        bui.buttonwidget(
439            edit=self.button,
440            color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5),
441        )
442        bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
443        bui.textwidget(
444            edit=self.prize_range_1_text,
445            text='-' if pr1 == '' else pr1,
446            position=(
447                self.button_x + 365 + x_offs,
448                self.button_y + self.button_scale_y - 93 + prize_y_offs,
449            ),
450        )
451
452        # We want to draw values containing tickets a bit smaller
453        # (scratch that; we now draw medals a bit bigger).
454        ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
455        prize_value_scale_large = 1.0
456        prize_value_scale_small = 1.0
457
458        bui.textwidget(
459            edit=self.prize_value_1_text,
460            text='-' if pv1 == '' else pv1,
461            scale=(
462                prize_value_scale_large
463                if ticket_char not in pv1
464                else prize_value_scale_small
465            ),
466            position=(
467                self.button_x + 380 + x_offs,
468                self.button_y + self.button_scale_y - 93 + prize_y_offs,
469            ),
470        )
471
472        bui.textwidget(
473            edit=self.prize_range_2_text,
474            text=pr2,
475            position=(
476                self.button_x + 365 + x_offs,
477                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
478            ),
479        )
480        bui.textwidget(
481            edit=self.prize_value_2_text,
482            text=pv2,
483            scale=(
484                prize_value_scale_large
485                if ticket_char not in pv2
486                else prize_value_scale_small
487            ),
488            position=(
489                self.button_x + 380 + x_offs,
490                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
491            ),
492        )
493
494        bui.textwidget(
495            edit=self.prize_range_3_text,
496            text=pr3,
497            position=(
498                self.button_x + 365 + x_offs,
499                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
500            ),
501        )
502        bui.textwidget(
503            edit=self.prize_value_3_text,
504            text=pv3,
505            scale=(
506                prize_value_scale_large
507                if ticket_char not in pv3
508                else prize_value_scale_small
509            ),
510            position=(
511                self.button_x + 380 + x_offs,
512                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
513            ),
514        )
515
516        leader_name = '-'
517        leader_score: str | bui.Lstr = '-'
518        if entry['scores']:
519            score = self.leader = copy.deepcopy(entry['scores'][0])
520            leader_name = score[1]
521            leader_score = (
522                bui.timestring((score[0] * 10) / 1000.0, centi=True)
523                if entry['scoreType'] == 'time'
524                else str(score[0])
525            )
526        else:
527            self.leader = None
528
529        bui.textwidget(
530            edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name)
531        )
532        bui.textwidget(edit=self.current_leader_score_text, text=leader_score)
533        bui.buttonwidget(
534            edit=self.more_scores_button,
535            label=bui.Lstr(resource=self._r + '.seeMoreText'),
536        )
537        out_of_time_text: str | bui.Lstr = (
538            '-'
539            if 'totalTime' not in entry
540            else bui.Lstr(
541                resource=self._r + '.ofTotalTimeText',
542                subs=[
543                    (
544                        '${TOTAL}',
545                        bui.timestring(entry['totalTime'], centi=False),
546                    )
547                ],
548            )
549        )
550        bui.textwidget(
551            edit=self.time_remaining_out_of_text, text=out_of_time_text
552        )
553
554        self.time_remaining = entry['timeRemaining']
555        self.has_time_remaining = entry is not None
556        self.tournament_id = entry['tournamentID']
557        self.required_league = (
558            None if 'requiredLeague' not in entry else entry['requiredLeague']
559        )
560
561        assert bui.app.classic is not None
562        game = bui.app.classic.accounts.tournament_info[self.tournament_id][
563            'game'
564        ]
565
566        if game is None:
567            bui.textwidget(edit=self.button_text, text='-')
568            bui.imagewidget(
569                edit=self.image, texture=bui.gettexture('black'), opacity=0.2
570            )
571        else:
572            campaignname, levelname = game.split(':')
573            campaign = bui.app.classic.getcampaign(campaignname)
574            max_players = bui.app.classic.accounts.tournament_info[
575                self.tournament_id
576            ]['maxPlayers']
577            txt = bui.Lstr(
578                value='${A} ${B}',
579                subs=[
580                    ('${A}', campaign.getlevel(levelname).displayname),
581                    (
582                        '${B}',
583                        bui.Lstr(
584                            resource='playerCountAbbreviatedText',
585                            subs=[('${COUNT}', str(max_players))],
586                        ),
587                    ),
588                ],
589            )
590            bui.textwidget(edit=self.button_text, text=txt)
591            bui.imagewidget(
592                edit=self.image,
593                texture=bui.gettexture(
594                    campaign.getlevel(levelname).preview_texture_name
595                ),
596                opacity=1.0 if enabled else 0.5,
597            )
598
599        fee = entry['fee']
600
601        if fee is None:
602            fee_var = None
603        elif fee == 4:
604            fee_var = 'price.tournament_entry_4'
605        elif fee == 3:
606            fee_var = 'price.tournament_entry_3'
607        elif fee == 2:
608            fee_var = 'price.tournament_entry_2'
609        elif fee == 1:
610            fee_var = 'price.tournament_entry_1'
611        else:
612            if fee != 0:
613                print('Unknown fee value:', fee)
614            fee_var = 'price.tournament_entry_0'
615
616        self.allow_ads = allow_ads = entry['allowAds']
617
618        final_fee: int | None = (
619            None
620            if fee_var is None
621            else plus.get_v1_account_misc_read_val(fee_var, '?')
622        )
623
624        final_fee_str: str | bui.Lstr
625        if fee_var is None:
626            final_fee_str = ''
627        else:
628            if final_fee == 0:
629                final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText')
630            else:
631                final_fee_str = bui.charstr(
632                    bui.SpecialChar.TICKET_BACKING
633                ) + str(final_fee)
634
635        assert bui.app.classic is not None
636        ad_tries_remaining = bui.app.classic.accounts.tournament_info[
637            self.tournament_id
638        ]['adTriesRemaining']
639        free_tries_remaining = bui.app.classic.accounts.tournament_info[
640            self.tournament_id
641        ]['freeTriesRemaining']
642
643        # Now, if this fee allows ads and we support video ads, show
644        # the 'or ad' version.
645        if allow_ads and plus.has_video_ads():
646            ads_enabled = plus.have_incentivized_ad()
647            bui.imagewidget(
648                edit=self.entry_fee_ad_image,
649                opacity=1.0 if ads_enabled else 0.25,
650            )
651            or_text = (
652                bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
653                .evaluate()
654                .strip()
655            )
656            bui.textwidget(edit=self.entry_fee_text_or, text=or_text)
657            bui.textwidget(
658                edit=self.entry_fee_text_top,
659                position=(
660                    self.button_x + 360,
661                    self.button_y + self.button_scale_y - 60,
662                ),
663                scale=1.3,
664                text=final_fee_str,
665            )
666
667            # Possibly show number of ad-plays remaining.
668            bui.textwidget(
669                edit=self.entry_fee_text_remaining,
670                position=(
671                    self.button_x + 360,
672                    self.button_y + self.button_scale_y - 146,
673                ),
674                text=(
675                    ''
676                    if ad_tries_remaining in [None, 0]
677                    else ('' + str(ad_tries_remaining))
678                ),
679                color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2),
680            )
681        else:
682            bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
683            bui.textwidget(edit=self.entry_fee_text_or, text='')
684            bui.textwidget(
685                edit=self.entry_fee_text_top,
686                position=(
687                    self.button_x + 360,
688                    self.button_y + self.button_scale_y - 80,
689                ),
690                scale=1.3,
691                text=final_fee_str,
692            )
693
694            # Possibly show number of free-plays remaining.
695            bui.textwidget(
696                edit=self.entry_fee_text_remaining,
697                position=(
698                    self.button_x + 360,
699                    self.button_y + self.button_scale_y - 100,
700                ),
701                text=(
702                    ''
703                    if (free_tries_remaining in [None, 0] or final_fee != 0)
704                    else ('' + str(free_tries_remaining))
705                ),
706                color=(0.6, 0.6, 0.6, 1),
707            )
class TournamentButton:
 17class TournamentButton:
 18    """Button showing a tournament in coop window."""
 19
 20    def __init__(
 21        self,
 22        parent: bui.Widget,
 23        x: float,
 24        y: float,
 25        select: bool,
 26        on_pressed: Callable[[TournamentButton], None],
 27    ) -> None:
 28        self._r = 'coopSelectWindow'
 29        sclx = 300
 30        scly = 195.0
 31        self.on_pressed = on_pressed
 32        self.lsbt = bui.getmesh('level_select_button_transparent')
 33        self.lsbo = bui.getmesh('level_select_button_opaque')
 34        self.allow_ads = False
 35        self.tournament_id: str | None = None
 36        self.time_remaining: int = 0
 37        self.has_time_remaining: bool = False
 38        self.leader: Any = None
 39        self.required_league: str | None = None
 40        self.button = btn = bui.buttonwidget(
 41            parent=parent,
 42            position=(x + 23, y + 4),
 43            size=(sclx, scly),
 44            label='',
 45            button_type='square',
 46            autoselect=True,
 47            on_activate_call=bui.WeakCall(self._pressed),
 48        )
 49        bui.widget(
 50            edit=btn,
 51            show_buffer_bottom=50,
 52            show_buffer_top=50,
 53            show_buffer_left=400,
 54            show_buffer_right=200,
 55        )
 56        if select:
 57            bui.containerwidget(
 58                edit=parent, selected_child=btn, visible_child=btn
 59            )
 60        image_width = sclx * 0.85 * 0.75
 61
 62        self.image = bui.imagewidget(
 63            parent=parent,
 64            draw_controller=btn,
 65            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
 66            size=(image_width, image_width * 0.5),
 67            mesh_transparent=self.lsbt,
 68            mesh_opaque=self.lsbo,
 69            texture=bui.gettexture('black'),
 70            opacity=0.2,
 71            mask_texture=bui.gettexture('mapPreviewMask'),
 72        )
 73
 74        self.lock_image = bui.imagewidget(
 75            parent=parent,
 76            draw_controller=btn,
 77            position=(x + 21 + sclx * 0.5 - image_width * 0.25, y + scly - 150),
 78            size=(image_width * 0.5, image_width * 0.5),
 79            texture=bui.gettexture('lock'),
 80            opacity=0.0,
 81        )
 82
 83        self.button_text = bui.textwidget(
 84            parent=parent,
 85            draw_controller=btn,
 86            position=(x + 20 + sclx * 0.5, y + scly - 35),
 87            size=(0, 0),
 88            h_align='center',
 89            text='-',
 90            v_align='center',
 91            maxwidth=sclx * 0.76,
 92            scale=0.85,
 93            color=(0.8, 1.0, 0.8, 1.0),
 94        )
 95
 96        header_color = (0.43, 0.4, 0.5, 1)
 97        value_color = (0.6, 0.6, 0.6, 1)
 98
 99        x_offs = 0
100        bui.textwidget(
101            parent=parent,
102            draw_controller=btn,
103            position=(x + 360, y + scly - 20),
104            size=(0, 0),
105            h_align='center',
106            text=bui.Lstr(resource=self._r + '.entryFeeText'),
107            v_align='center',
108            maxwidth=100,
109            scale=0.9,
110            color=header_color,
111            flatness=1.0,
112        )
113
114        self.entry_fee_text_top = bui.textwidget(
115            parent=parent,
116            draw_controller=btn,
117            position=(x + 360, y + scly - 60),
118            size=(0, 0),
119            h_align='center',
120            text='-',
121            v_align='center',
122            maxwidth=60,
123            scale=1.3,
124            color=value_color,
125            flatness=1.0,
126        )
127        self.entry_fee_text_or = bui.textwidget(
128            parent=parent,
129            draw_controller=btn,
130            position=(x + 360, y + scly - 90),
131            size=(0, 0),
132            h_align='center',
133            text='',
134            v_align='center',
135            maxwidth=60,
136            scale=0.5,
137            color=value_color,
138            flatness=1.0,
139        )
140        self.entry_fee_text_remaining = bui.textwidget(
141            parent=parent,
142            draw_controller=btn,
143            position=(x + 360, y + scly - 90),
144            size=(0, 0),
145            h_align='center',
146            text='',
147            v_align='center',
148            maxwidth=60,
149            scale=0.5,
150            color=value_color,
151            flatness=1.0,
152        )
153
154        self.entry_fee_ad_image = bui.imagewidget(
155            parent=parent,
156            size=(40, 40),
157            draw_controller=btn,
158            position=(x + 360 - 20, y + scly - 140),
159            opacity=0.0,
160            texture=bui.gettexture('tv'),
161        )
162
163        x_offs += 50
164
165        bui.textwidget(
166            parent=parent,
167            draw_controller=btn,
168            position=(x + 447 + x_offs, y + scly - 20),
169            size=(0, 0),
170            h_align='center',
171            text=bui.Lstr(resource=self._r + '.prizesText'),
172            v_align='center',
173            maxwidth=130,
174            scale=0.9,
175            color=header_color,
176            flatness=1.0,
177        )
178
179        self.button_x = x
180        self.button_y = y
181        self.button_scale_y = scly
182
183        xo2 = 0
184        prize_value_scale = 1.5
185
186        self.prize_range_1_text = bui.textwidget(
187            parent=parent,
188            draw_controller=btn,
189            position=(x + 355 + xo2 + x_offs, y + scly - 93),
190            size=(0, 0),
191            h_align='right',
192            v_align='center',
193            maxwidth=50,
194            text='-',
195            scale=0.8,
196            color=header_color,
197            flatness=1.0,
198        )
199        self.prize_value_1_text = bui.textwidget(
200            parent=parent,
201            draw_controller=btn,
202            position=(x + 380 + xo2 + x_offs, y + scly - 93),
203            size=(0, 0),
204            h_align='left',
205            text='-',
206            v_align='center',
207            maxwidth=100,
208            scale=prize_value_scale,
209            color=value_color,
210            flatness=1.0,
211        )
212
213        self.prize_range_2_text = bui.textwidget(
214            parent=parent,
215            draw_controller=btn,
216            position=(x + 355 + xo2 + x_offs, y + scly - 93),
217            size=(0, 0),
218            h_align='right',
219            v_align='center',
220            maxwidth=50,
221            scale=0.8,
222            color=header_color,
223            flatness=1.0,
224        )
225        self.prize_value_2_text = bui.textwidget(
226            parent=parent,
227            draw_controller=btn,
228            position=(x + 380 + xo2 + x_offs, y + scly - 93),
229            size=(0, 0),
230            h_align='left',
231            text='',
232            v_align='center',
233            maxwidth=100,
234            scale=prize_value_scale,
235            color=value_color,
236            flatness=1.0,
237        )
238
239        self.prize_range_3_text = bui.textwidget(
240            parent=parent,
241            draw_controller=btn,
242            position=(x + 355 + xo2 + x_offs, y + scly - 93),
243            size=(0, 0),
244            h_align='right',
245            v_align='center',
246            maxwidth=50,
247            scale=0.8,
248            color=header_color,
249            flatness=1.0,
250        )
251        self.prize_value_3_text = bui.textwidget(
252            parent=parent,
253            draw_controller=btn,
254            position=(x + 380 + xo2 + x_offs, y + scly - 93),
255            size=(0, 0),
256            h_align='left',
257            text='',
258            v_align='center',
259            maxwidth=100,
260            scale=prize_value_scale,
261            color=value_color,
262            flatness=1.0,
263        )
264
265        bui.textwidget(
266            parent=parent,
267            draw_controller=btn,
268            position=(x + 620 + x_offs, y + scly - 20),
269            size=(0, 0),
270            h_align='center',
271            text=bui.Lstr(resource=self._r + '.currentBestText'),
272            v_align='center',
273            maxwidth=180,
274            scale=0.9,
275            color=header_color,
276            flatness=1.0,
277        )
278        self.current_leader_name_text = bui.textwidget(
279            parent=parent,
280            draw_controller=btn,
281            position=(
282                x + 620 + x_offs - (170 / 1.4) * 0.5,
283                y + scly - 60 - 40 * 0.5,
284            ),
285            selectable=True,
286            click_activate=True,
287            autoselect=True,
288            on_activate_call=bui.WeakCall(self._show_leader),
289            size=(170 / 1.4, 40),
290            h_align='center',
291            text='-',
292            v_align='center',
293            maxwidth=170,
294            scale=1.4,
295            color=value_color,
296            flatness=1.0,
297        )
298        self.current_leader_score_text = bui.textwidget(
299            parent=parent,
300            draw_controller=btn,
301            position=(x + 620 + x_offs, y + scly - 113 + 10),
302            size=(0, 0),
303            h_align='center',
304            text='-',
305            v_align='center',
306            maxwidth=170,
307            scale=1.8,
308            color=value_color,
309            flatness=1.0,
310        )
311
312        self.more_scores_button = bui.buttonwidget(
313            parent=parent,
314            position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
315            color=(0.5, 0.5, 0.6),
316            textcolor=(0.7, 0.7, 0.8),
317            label='-',
318            size=(120, 40),
319            autoselect=True,
320            up_widget=self.current_leader_name_text,
321            text_scale=0.6,
322            on_activate_call=bui.WeakCall(self._show_scores),
323        )
324        bui.widget(
325            edit=self.current_leader_name_text,
326            down_widget=self.more_scores_button,
327        )
328
329        bui.textwidget(
330            parent=parent,
331            draw_controller=btn,
332            position=(x + 820 + x_offs, y + scly - 20),
333            size=(0, 0),
334            h_align='center',
335            text=bui.Lstr(resource=self._r + '.timeRemainingText'),
336            v_align='center',
337            maxwidth=180,
338            scale=0.9,
339            color=header_color,
340            flatness=1.0,
341        )
342        self.time_remaining_value_text = bui.textwidget(
343            parent=parent,
344            draw_controller=btn,
345            position=(x + 820 + x_offs, y + scly - 68),
346            size=(0, 0),
347            h_align='center',
348            text='-',
349            v_align='center',
350            maxwidth=180,
351            scale=2.0,
352            color=value_color,
353            flatness=1.0,
354        )
355        self.time_remaining_out_of_text = bui.textwidget(
356            parent=parent,
357            draw_controller=btn,
358            position=(x + 820 + x_offs, y + scly - 110),
359            size=(0, 0),
360            h_align='center',
361            text='-',
362            v_align='center',
363            maxwidth=120,
364            scale=0.72,
365            color=(0.4, 0.4, 0.5),
366            flatness=1.0,
367        )
368
369    def _pressed(self) -> None:
370        self.on_pressed(self)
371
372    def _show_leader(self) -> None:
373        # pylint: disable=cyclic-import
374        from bauiv1lib.account.viewer import AccountViewerWindow
375
376        tournament_id = self.tournament_id
377
378        # FIXME: This assumes a single player entry in leader; should expand
379        #  this to work with multiple.
380        if (
381            tournament_id is None
382            or self.leader is None
383            or len(self.leader[2]) != 1
384        ):
385            bui.getsound('error').play()
386            return
387        bui.getsound('swish').play()
388        AccountViewerWindow(
389            account_id=self.leader[2][0].get('a', None),
390            profile_id=self.leader[2][0].get('p', None),
391            position=self.current_leader_name_text.get_screen_space_center(),
392        )
393
394    def _show_scores(self) -> None:
395        # pylint: disable=cyclic-import
396        from bauiv1lib.tournamentscores import TournamentScoresWindow
397
398        tournament_id = self.tournament_id
399        if tournament_id is None:
400            bui.getsound('error').play()
401            return
402
403        TournamentScoresWindow(
404            tournament_id=tournament_id,
405            position=self.more_scores_button.get_screen_space_center(),
406        )
407
408    def update_for_data(self, entry: dict[str, Any]) -> None:
409        """Update for new incoming data."""
410        # pylint: disable=too-many-statements
411        # pylint: disable=too-many-locals
412        # pylint: disable=too-many-branches
413
414        plus = bui.app.plus
415        assert plus is not None
416
417        assert bui.app.classic is not None
418        prize_y_offs = (
419            34
420            if 'prizeRange3' in entry
421            else 20 if 'prizeRange2' in entry else 12
422        )
423        x_offs = 90
424
425        # pylint: disable=useless-suppression
426        # pylint: disable=unbalanced-tuple-unpacking
427        (
428            pr1,
429            pv1,
430            pr2,
431            pv2,
432            pr3,
433            pv3,
434        ) = bui.app.classic.get_tournament_prize_strings(entry)
435        # pylint: enable=unbalanced-tuple-unpacking
436        # pylint: enable=useless-suppression
437
438        enabled = 'requiredLeague' not in entry
439        bui.buttonwidget(
440            edit=self.button,
441            color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5),
442        )
443        bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
444        bui.textwidget(
445            edit=self.prize_range_1_text,
446            text='-' if pr1 == '' else pr1,
447            position=(
448                self.button_x + 365 + x_offs,
449                self.button_y + self.button_scale_y - 93 + prize_y_offs,
450            ),
451        )
452
453        # We want to draw values containing tickets a bit smaller
454        # (scratch that; we now draw medals a bit bigger).
455        ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
456        prize_value_scale_large = 1.0
457        prize_value_scale_small = 1.0
458
459        bui.textwidget(
460            edit=self.prize_value_1_text,
461            text='-' if pv1 == '' else pv1,
462            scale=(
463                prize_value_scale_large
464                if ticket_char not in pv1
465                else prize_value_scale_small
466            ),
467            position=(
468                self.button_x + 380 + x_offs,
469                self.button_y + self.button_scale_y - 93 + prize_y_offs,
470            ),
471        )
472
473        bui.textwidget(
474            edit=self.prize_range_2_text,
475            text=pr2,
476            position=(
477                self.button_x + 365 + x_offs,
478                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
479            ),
480        )
481        bui.textwidget(
482            edit=self.prize_value_2_text,
483            text=pv2,
484            scale=(
485                prize_value_scale_large
486                if ticket_char not in pv2
487                else prize_value_scale_small
488            ),
489            position=(
490                self.button_x + 380 + x_offs,
491                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
492            ),
493        )
494
495        bui.textwidget(
496            edit=self.prize_range_3_text,
497            text=pr3,
498            position=(
499                self.button_x + 365 + x_offs,
500                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
501            ),
502        )
503        bui.textwidget(
504            edit=self.prize_value_3_text,
505            text=pv3,
506            scale=(
507                prize_value_scale_large
508                if ticket_char not in pv3
509                else prize_value_scale_small
510            ),
511            position=(
512                self.button_x + 380 + x_offs,
513                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
514            ),
515        )
516
517        leader_name = '-'
518        leader_score: str | bui.Lstr = '-'
519        if entry['scores']:
520            score = self.leader = copy.deepcopy(entry['scores'][0])
521            leader_name = score[1]
522            leader_score = (
523                bui.timestring((score[0] * 10) / 1000.0, centi=True)
524                if entry['scoreType'] == 'time'
525                else str(score[0])
526            )
527        else:
528            self.leader = None
529
530        bui.textwidget(
531            edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name)
532        )
533        bui.textwidget(edit=self.current_leader_score_text, text=leader_score)
534        bui.buttonwidget(
535            edit=self.more_scores_button,
536            label=bui.Lstr(resource=self._r + '.seeMoreText'),
537        )
538        out_of_time_text: str | bui.Lstr = (
539            '-'
540            if 'totalTime' not in entry
541            else bui.Lstr(
542                resource=self._r + '.ofTotalTimeText',
543                subs=[
544                    (
545                        '${TOTAL}',
546                        bui.timestring(entry['totalTime'], centi=False),
547                    )
548                ],
549            )
550        )
551        bui.textwidget(
552            edit=self.time_remaining_out_of_text, text=out_of_time_text
553        )
554
555        self.time_remaining = entry['timeRemaining']
556        self.has_time_remaining = entry is not None
557        self.tournament_id = entry['tournamentID']
558        self.required_league = (
559            None if 'requiredLeague' not in entry else entry['requiredLeague']
560        )
561
562        assert bui.app.classic is not None
563        game = bui.app.classic.accounts.tournament_info[self.tournament_id][
564            'game'
565        ]
566
567        if game is None:
568            bui.textwidget(edit=self.button_text, text='-')
569            bui.imagewidget(
570                edit=self.image, texture=bui.gettexture('black'), opacity=0.2
571            )
572        else:
573            campaignname, levelname = game.split(':')
574            campaign = bui.app.classic.getcampaign(campaignname)
575            max_players = bui.app.classic.accounts.tournament_info[
576                self.tournament_id
577            ]['maxPlayers']
578            txt = bui.Lstr(
579                value='${A} ${B}',
580                subs=[
581                    ('${A}', campaign.getlevel(levelname).displayname),
582                    (
583                        '${B}',
584                        bui.Lstr(
585                            resource='playerCountAbbreviatedText',
586                            subs=[('${COUNT}', str(max_players))],
587                        ),
588                    ),
589                ],
590            )
591            bui.textwidget(edit=self.button_text, text=txt)
592            bui.imagewidget(
593                edit=self.image,
594                texture=bui.gettexture(
595                    campaign.getlevel(levelname).preview_texture_name
596                ),
597                opacity=1.0 if enabled else 0.5,
598            )
599
600        fee = entry['fee']
601
602        if fee is None:
603            fee_var = None
604        elif fee == 4:
605            fee_var = 'price.tournament_entry_4'
606        elif fee == 3:
607            fee_var = 'price.tournament_entry_3'
608        elif fee == 2:
609            fee_var = 'price.tournament_entry_2'
610        elif fee == 1:
611            fee_var = 'price.tournament_entry_1'
612        else:
613            if fee != 0:
614                print('Unknown fee value:', fee)
615            fee_var = 'price.tournament_entry_0'
616
617        self.allow_ads = allow_ads = entry['allowAds']
618
619        final_fee: int | None = (
620            None
621            if fee_var is None
622            else plus.get_v1_account_misc_read_val(fee_var, '?')
623        )
624
625        final_fee_str: str | bui.Lstr
626        if fee_var is None:
627            final_fee_str = ''
628        else:
629            if final_fee == 0:
630                final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText')
631            else:
632                final_fee_str = bui.charstr(
633                    bui.SpecialChar.TICKET_BACKING
634                ) + str(final_fee)
635
636        assert bui.app.classic is not None
637        ad_tries_remaining = bui.app.classic.accounts.tournament_info[
638            self.tournament_id
639        ]['adTriesRemaining']
640        free_tries_remaining = bui.app.classic.accounts.tournament_info[
641            self.tournament_id
642        ]['freeTriesRemaining']
643
644        # Now, if this fee allows ads and we support video ads, show
645        # the 'or ad' version.
646        if allow_ads and plus.has_video_ads():
647            ads_enabled = plus.have_incentivized_ad()
648            bui.imagewidget(
649                edit=self.entry_fee_ad_image,
650                opacity=1.0 if ads_enabled else 0.25,
651            )
652            or_text = (
653                bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
654                .evaluate()
655                .strip()
656            )
657            bui.textwidget(edit=self.entry_fee_text_or, text=or_text)
658            bui.textwidget(
659                edit=self.entry_fee_text_top,
660                position=(
661                    self.button_x + 360,
662                    self.button_y + self.button_scale_y - 60,
663                ),
664                scale=1.3,
665                text=final_fee_str,
666            )
667
668            # Possibly show number of ad-plays remaining.
669            bui.textwidget(
670                edit=self.entry_fee_text_remaining,
671                position=(
672                    self.button_x + 360,
673                    self.button_y + self.button_scale_y - 146,
674                ),
675                text=(
676                    ''
677                    if ad_tries_remaining in [None, 0]
678                    else ('' + str(ad_tries_remaining))
679                ),
680                color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2),
681            )
682        else:
683            bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
684            bui.textwidget(edit=self.entry_fee_text_or, text='')
685            bui.textwidget(
686                edit=self.entry_fee_text_top,
687                position=(
688                    self.button_x + 360,
689                    self.button_y + self.button_scale_y - 80,
690                ),
691                scale=1.3,
692                text=final_fee_str,
693            )
694
695            # Possibly show number of free-plays remaining.
696            bui.textwidget(
697                edit=self.entry_fee_text_remaining,
698                position=(
699                    self.button_x + 360,
700                    self.button_y + self.button_scale_y - 100,
701                ),
702                text=(
703                    ''
704                    if (free_tries_remaining in [None, 0] or final_fee != 0)
705                    else ('' + str(free_tries_remaining))
706                ),
707                color=(0.6, 0.6, 0.6, 1),
708            )

Button showing a tournament in coop window.

TournamentButton( parent: _bauiv1.Widget, x: float, y: float, select: bool, on_pressed: Callable[[TournamentButton], NoneType])
 20    def __init__(
 21        self,
 22        parent: bui.Widget,
 23        x: float,
 24        y: float,
 25        select: bool,
 26        on_pressed: Callable[[TournamentButton], None],
 27    ) -> None:
 28        self._r = 'coopSelectWindow'
 29        sclx = 300
 30        scly = 195.0
 31        self.on_pressed = on_pressed
 32        self.lsbt = bui.getmesh('level_select_button_transparent')
 33        self.lsbo = bui.getmesh('level_select_button_opaque')
 34        self.allow_ads = False
 35        self.tournament_id: str | None = None
 36        self.time_remaining: int = 0
 37        self.has_time_remaining: bool = False
 38        self.leader: Any = None
 39        self.required_league: str | None = None
 40        self.button = btn = bui.buttonwidget(
 41            parent=parent,
 42            position=(x + 23, y + 4),
 43            size=(sclx, scly),
 44            label='',
 45            button_type='square',
 46            autoselect=True,
 47            on_activate_call=bui.WeakCall(self._pressed),
 48        )
 49        bui.widget(
 50            edit=btn,
 51            show_buffer_bottom=50,
 52            show_buffer_top=50,
 53            show_buffer_left=400,
 54            show_buffer_right=200,
 55        )
 56        if select:
 57            bui.containerwidget(
 58                edit=parent, selected_child=btn, visible_child=btn
 59            )
 60        image_width = sclx * 0.85 * 0.75
 61
 62        self.image = bui.imagewidget(
 63            parent=parent,
 64            draw_controller=btn,
 65            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
 66            size=(image_width, image_width * 0.5),
 67            mesh_transparent=self.lsbt,
 68            mesh_opaque=self.lsbo,
 69            texture=bui.gettexture('black'),
 70            opacity=0.2,
 71            mask_texture=bui.gettexture('mapPreviewMask'),
 72        )
 73
 74        self.lock_image = bui.imagewidget(
 75            parent=parent,
 76            draw_controller=btn,
 77            position=(x + 21 + sclx * 0.5 - image_width * 0.25, y + scly - 150),
 78            size=(image_width * 0.5, image_width * 0.5),
 79            texture=bui.gettexture('lock'),
 80            opacity=0.0,
 81        )
 82
 83        self.button_text = bui.textwidget(
 84            parent=parent,
 85            draw_controller=btn,
 86            position=(x + 20 + sclx * 0.5, y + scly - 35),
 87            size=(0, 0),
 88            h_align='center',
 89            text='-',
 90            v_align='center',
 91            maxwidth=sclx * 0.76,
 92            scale=0.85,
 93            color=(0.8, 1.0, 0.8, 1.0),
 94        )
 95
 96        header_color = (0.43, 0.4, 0.5, 1)
 97        value_color = (0.6, 0.6, 0.6, 1)
 98
 99        x_offs = 0
100        bui.textwidget(
101            parent=parent,
102            draw_controller=btn,
103            position=(x + 360, y + scly - 20),
104            size=(0, 0),
105            h_align='center',
106            text=bui.Lstr(resource=self._r + '.entryFeeText'),
107            v_align='center',
108            maxwidth=100,
109            scale=0.9,
110            color=header_color,
111            flatness=1.0,
112        )
113
114        self.entry_fee_text_top = bui.textwidget(
115            parent=parent,
116            draw_controller=btn,
117            position=(x + 360, y + scly - 60),
118            size=(0, 0),
119            h_align='center',
120            text='-',
121            v_align='center',
122            maxwidth=60,
123            scale=1.3,
124            color=value_color,
125            flatness=1.0,
126        )
127        self.entry_fee_text_or = bui.textwidget(
128            parent=parent,
129            draw_controller=btn,
130            position=(x + 360, y + scly - 90),
131            size=(0, 0),
132            h_align='center',
133            text='',
134            v_align='center',
135            maxwidth=60,
136            scale=0.5,
137            color=value_color,
138            flatness=1.0,
139        )
140        self.entry_fee_text_remaining = bui.textwidget(
141            parent=parent,
142            draw_controller=btn,
143            position=(x + 360, y + scly - 90),
144            size=(0, 0),
145            h_align='center',
146            text='',
147            v_align='center',
148            maxwidth=60,
149            scale=0.5,
150            color=value_color,
151            flatness=1.0,
152        )
153
154        self.entry_fee_ad_image = bui.imagewidget(
155            parent=parent,
156            size=(40, 40),
157            draw_controller=btn,
158            position=(x + 360 - 20, y + scly - 140),
159            opacity=0.0,
160            texture=bui.gettexture('tv'),
161        )
162
163        x_offs += 50
164
165        bui.textwidget(
166            parent=parent,
167            draw_controller=btn,
168            position=(x + 447 + x_offs, y + scly - 20),
169            size=(0, 0),
170            h_align='center',
171            text=bui.Lstr(resource=self._r + '.prizesText'),
172            v_align='center',
173            maxwidth=130,
174            scale=0.9,
175            color=header_color,
176            flatness=1.0,
177        )
178
179        self.button_x = x
180        self.button_y = y
181        self.button_scale_y = scly
182
183        xo2 = 0
184        prize_value_scale = 1.5
185
186        self.prize_range_1_text = bui.textwidget(
187            parent=parent,
188            draw_controller=btn,
189            position=(x + 355 + xo2 + x_offs, y + scly - 93),
190            size=(0, 0),
191            h_align='right',
192            v_align='center',
193            maxwidth=50,
194            text='-',
195            scale=0.8,
196            color=header_color,
197            flatness=1.0,
198        )
199        self.prize_value_1_text = bui.textwidget(
200            parent=parent,
201            draw_controller=btn,
202            position=(x + 380 + xo2 + x_offs, y + scly - 93),
203            size=(0, 0),
204            h_align='left',
205            text='-',
206            v_align='center',
207            maxwidth=100,
208            scale=prize_value_scale,
209            color=value_color,
210            flatness=1.0,
211        )
212
213        self.prize_range_2_text = bui.textwidget(
214            parent=parent,
215            draw_controller=btn,
216            position=(x + 355 + xo2 + x_offs, y + scly - 93),
217            size=(0, 0),
218            h_align='right',
219            v_align='center',
220            maxwidth=50,
221            scale=0.8,
222            color=header_color,
223            flatness=1.0,
224        )
225        self.prize_value_2_text = bui.textwidget(
226            parent=parent,
227            draw_controller=btn,
228            position=(x + 380 + xo2 + x_offs, y + scly - 93),
229            size=(0, 0),
230            h_align='left',
231            text='',
232            v_align='center',
233            maxwidth=100,
234            scale=prize_value_scale,
235            color=value_color,
236            flatness=1.0,
237        )
238
239        self.prize_range_3_text = bui.textwidget(
240            parent=parent,
241            draw_controller=btn,
242            position=(x + 355 + xo2 + x_offs, y + scly - 93),
243            size=(0, 0),
244            h_align='right',
245            v_align='center',
246            maxwidth=50,
247            scale=0.8,
248            color=header_color,
249            flatness=1.0,
250        )
251        self.prize_value_3_text = bui.textwidget(
252            parent=parent,
253            draw_controller=btn,
254            position=(x + 380 + xo2 + x_offs, y + scly - 93),
255            size=(0, 0),
256            h_align='left',
257            text='',
258            v_align='center',
259            maxwidth=100,
260            scale=prize_value_scale,
261            color=value_color,
262            flatness=1.0,
263        )
264
265        bui.textwidget(
266            parent=parent,
267            draw_controller=btn,
268            position=(x + 620 + x_offs, y + scly - 20),
269            size=(0, 0),
270            h_align='center',
271            text=bui.Lstr(resource=self._r + '.currentBestText'),
272            v_align='center',
273            maxwidth=180,
274            scale=0.9,
275            color=header_color,
276            flatness=1.0,
277        )
278        self.current_leader_name_text = bui.textwidget(
279            parent=parent,
280            draw_controller=btn,
281            position=(
282                x + 620 + x_offs - (170 / 1.4) * 0.5,
283                y + scly - 60 - 40 * 0.5,
284            ),
285            selectable=True,
286            click_activate=True,
287            autoselect=True,
288            on_activate_call=bui.WeakCall(self._show_leader),
289            size=(170 / 1.4, 40),
290            h_align='center',
291            text='-',
292            v_align='center',
293            maxwidth=170,
294            scale=1.4,
295            color=value_color,
296            flatness=1.0,
297        )
298        self.current_leader_score_text = bui.textwidget(
299            parent=parent,
300            draw_controller=btn,
301            position=(x + 620 + x_offs, y + scly - 113 + 10),
302            size=(0, 0),
303            h_align='center',
304            text='-',
305            v_align='center',
306            maxwidth=170,
307            scale=1.8,
308            color=value_color,
309            flatness=1.0,
310        )
311
312        self.more_scores_button = bui.buttonwidget(
313            parent=parent,
314            position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
315            color=(0.5, 0.5, 0.6),
316            textcolor=(0.7, 0.7, 0.8),
317            label='-',
318            size=(120, 40),
319            autoselect=True,
320            up_widget=self.current_leader_name_text,
321            text_scale=0.6,
322            on_activate_call=bui.WeakCall(self._show_scores),
323        )
324        bui.widget(
325            edit=self.current_leader_name_text,
326            down_widget=self.more_scores_button,
327        )
328
329        bui.textwidget(
330            parent=parent,
331            draw_controller=btn,
332            position=(x + 820 + x_offs, y + scly - 20),
333            size=(0, 0),
334            h_align='center',
335            text=bui.Lstr(resource=self._r + '.timeRemainingText'),
336            v_align='center',
337            maxwidth=180,
338            scale=0.9,
339            color=header_color,
340            flatness=1.0,
341        )
342        self.time_remaining_value_text = bui.textwidget(
343            parent=parent,
344            draw_controller=btn,
345            position=(x + 820 + x_offs, y + scly - 68),
346            size=(0, 0),
347            h_align='center',
348            text='-',
349            v_align='center',
350            maxwidth=180,
351            scale=2.0,
352            color=value_color,
353            flatness=1.0,
354        )
355        self.time_remaining_out_of_text = bui.textwidget(
356            parent=parent,
357            draw_controller=btn,
358            position=(x + 820 + x_offs, y + scly - 110),
359            size=(0, 0),
360            h_align='center',
361            text='-',
362            v_align='center',
363            maxwidth=120,
364            scale=0.72,
365            color=(0.4, 0.4, 0.5),
366            flatness=1.0,
367        )
on_pressed
lsbt
lsbo
allow_ads
tournament_id: str | None
time_remaining: int
has_time_remaining: bool
leader: Any
required_league: str | None
image
lock_image
button_text
entry_fee_text_top
entry_fee_text_or
entry_fee_text_remaining
entry_fee_ad_image
button_x
button_y
button_scale_y
prize_range_1_text
prize_value_1_text
prize_range_2_text
prize_value_2_text
prize_range_3_text
prize_value_3_text
current_leader_name_text
current_leader_score_text
more_scores_button
time_remaining_value_text
time_remaining_out_of_text
def update_for_data(self, entry: dict[str, typing.Any]) -> None:
408    def update_for_data(self, entry: dict[str, Any]) -> None:
409        """Update for new incoming data."""
410        # pylint: disable=too-many-statements
411        # pylint: disable=too-many-locals
412        # pylint: disable=too-many-branches
413
414        plus = bui.app.plus
415        assert plus is not None
416
417        assert bui.app.classic is not None
418        prize_y_offs = (
419            34
420            if 'prizeRange3' in entry
421            else 20 if 'prizeRange2' in entry else 12
422        )
423        x_offs = 90
424
425        # pylint: disable=useless-suppression
426        # pylint: disable=unbalanced-tuple-unpacking
427        (
428            pr1,
429            pv1,
430            pr2,
431            pv2,
432            pr3,
433            pv3,
434        ) = bui.app.classic.get_tournament_prize_strings(entry)
435        # pylint: enable=unbalanced-tuple-unpacking
436        # pylint: enable=useless-suppression
437
438        enabled = 'requiredLeague' not in entry
439        bui.buttonwidget(
440            edit=self.button,
441            color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5),
442        )
443        bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
444        bui.textwidget(
445            edit=self.prize_range_1_text,
446            text='-' if pr1 == '' else pr1,
447            position=(
448                self.button_x + 365 + x_offs,
449                self.button_y + self.button_scale_y - 93 + prize_y_offs,
450            ),
451        )
452
453        # We want to draw values containing tickets a bit smaller
454        # (scratch that; we now draw medals a bit bigger).
455        ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
456        prize_value_scale_large = 1.0
457        prize_value_scale_small = 1.0
458
459        bui.textwidget(
460            edit=self.prize_value_1_text,
461            text='-' if pv1 == '' else pv1,
462            scale=(
463                prize_value_scale_large
464                if ticket_char not in pv1
465                else prize_value_scale_small
466            ),
467            position=(
468                self.button_x + 380 + x_offs,
469                self.button_y + self.button_scale_y - 93 + prize_y_offs,
470            ),
471        )
472
473        bui.textwidget(
474            edit=self.prize_range_2_text,
475            text=pr2,
476            position=(
477                self.button_x + 365 + x_offs,
478                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
479            ),
480        )
481        bui.textwidget(
482            edit=self.prize_value_2_text,
483            text=pv2,
484            scale=(
485                prize_value_scale_large
486                if ticket_char not in pv2
487                else prize_value_scale_small
488            ),
489            position=(
490                self.button_x + 380 + x_offs,
491                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
492            ),
493        )
494
495        bui.textwidget(
496            edit=self.prize_range_3_text,
497            text=pr3,
498            position=(
499                self.button_x + 365 + x_offs,
500                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
501            ),
502        )
503        bui.textwidget(
504            edit=self.prize_value_3_text,
505            text=pv3,
506            scale=(
507                prize_value_scale_large
508                if ticket_char not in pv3
509                else prize_value_scale_small
510            ),
511            position=(
512                self.button_x + 380 + x_offs,
513                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
514            ),
515        )
516
517        leader_name = '-'
518        leader_score: str | bui.Lstr = '-'
519        if entry['scores']:
520            score = self.leader = copy.deepcopy(entry['scores'][0])
521            leader_name = score[1]
522            leader_score = (
523                bui.timestring((score[0] * 10) / 1000.0, centi=True)
524                if entry['scoreType'] == 'time'
525                else str(score[0])
526            )
527        else:
528            self.leader = None
529
530        bui.textwidget(
531            edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name)
532        )
533        bui.textwidget(edit=self.current_leader_score_text, text=leader_score)
534        bui.buttonwidget(
535            edit=self.more_scores_button,
536            label=bui.Lstr(resource=self._r + '.seeMoreText'),
537        )
538        out_of_time_text: str | bui.Lstr = (
539            '-'
540            if 'totalTime' not in entry
541            else bui.Lstr(
542                resource=self._r + '.ofTotalTimeText',
543                subs=[
544                    (
545                        '${TOTAL}',
546                        bui.timestring(entry['totalTime'], centi=False),
547                    )
548                ],
549            )
550        )
551        bui.textwidget(
552            edit=self.time_remaining_out_of_text, text=out_of_time_text
553        )
554
555        self.time_remaining = entry['timeRemaining']
556        self.has_time_remaining = entry is not None
557        self.tournament_id = entry['tournamentID']
558        self.required_league = (
559            None if 'requiredLeague' not in entry else entry['requiredLeague']
560        )
561
562        assert bui.app.classic is not None
563        game = bui.app.classic.accounts.tournament_info[self.tournament_id][
564            'game'
565        ]
566
567        if game is None:
568            bui.textwidget(edit=self.button_text, text='-')
569            bui.imagewidget(
570                edit=self.image, texture=bui.gettexture('black'), opacity=0.2
571            )
572        else:
573            campaignname, levelname = game.split(':')
574            campaign = bui.app.classic.getcampaign(campaignname)
575            max_players = bui.app.classic.accounts.tournament_info[
576                self.tournament_id
577            ]['maxPlayers']
578            txt = bui.Lstr(
579                value='${A} ${B}',
580                subs=[
581                    ('${A}', campaign.getlevel(levelname).displayname),
582                    (
583                        '${B}',
584                        bui.Lstr(
585                            resource='playerCountAbbreviatedText',
586                            subs=[('${COUNT}', str(max_players))],
587                        ),
588                    ),
589                ],
590            )
591            bui.textwidget(edit=self.button_text, text=txt)
592            bui.imagewidget(
593                edit=self.image,
594                texture=bui.gettexture(
595                    campaign.getlevel(levelname).preview_texture_name
596                ),
597                opacity=1.0 if enabled else 0.5,
598            )
599
600        fee = entry['fee']
601
602        if fee is None:
603            fee_var = None
604        elif fee == 4:
605            fee_var = 'price.tournament_entry_4'
606        elif fee == 3:
607            fee_var = 'price.tournament_entry_3'
608        elif fee == 2:
609            fee_var = 'price.tournament_entry_2'
610        elif fee == 1:
611            fee_var = 'price.tournament_entry_1'
612        else:
613            if fee != 0:
614                print('Unknown fee value:', fee)
615            fee_var = 'price.tournament_entry_0'
616
617        self.allow_ads = allow_ads = entry['allowAds']
618
619        final_fee: int | None = (
620            None
621            if fee_var is None
622            else plus.get_v1_account_misc_read_val(fee_var, '?')
623        )
624
625        final_fee_str: str | bui.Lstr
626        if fee_var is None:
627            final_fee_str = ''
628        else:
629            if final_fee == 0:
630                final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText')
631            else:
632                final_fee_str = bui.charstr(
633                    bui.SpecialChar.TICKET_BACKING
634                ) + str(final_fee)
635
636        assert bui.app.classic is not None
637        ad_tries_remaining = bui.app.classic.accounts.tournament_info[
638            self.tournament_id
639        ]['adTriesRemaining']
640        free_tries_remaining = bui.app.classic.accounts.tournament_info[
641            self.tournament_id
642        ]['freeTriesRemaining']
643
644        # Now, if this fee allows ads and we support video ads, show
645        # the 'or ad' version.
646        if allow_ads and plus.has_video_ads():
647            ads_enabled = plus.have_incentivized_ad()
648            bui.imagewidget(
649                edit=self.entry_fee_ad_image,
650                opacity=1.0 if ads_enabled else 0.25,
651            )
652            or_text = (
653                bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
654                .evaluate()
655                .strip()
656            )
657            bui.textwidget(edit=self.entry_fee_text_or, text=or_text)
658            bui.textwidget(
659                edit=self.entry_fee_text_top,
660                position=(
661                    self.button_x + 360,
662                    self.button_y + self.button_scale_y - 60,
663                ),
664                scale=1.3,
665                text=final_fee_str,
666            )
667
668            # Possibly show number of ad-plays remaining.
669            bui.textwidget(
670                edit=self.entry_fee_text_remaining,
671                position=(
672                    self.button_x + 360,
673                    self.button_y + self.button_scale_y - 146,
674                ),
675                text=(
676                    ''
677                    if ad_tries_remaining in [None, 0]
678                    else ('' + str(ad_tries_remaining))
679                ),
680                color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2),
681            )
682        else:
683            bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
684            bui.textwidget(edit=self.entry_fee_text_or, text='')
685            bui.textwidget(
686                edit=self.entry_fee_text_top,
687                position=(
688                    self.button_x + 360,
689                    self.button_y + self.button_scale_y - 80,
690                ),
691                scale=1.3,
692                text=final_fee_str,
693            )
694
695            # Possibly show number of free-plays remaining.
696            bui.textwidget(
697                edit=self.entry_fee_text_remaining,
698                position=(
699                    self.button_x + 360,
700                    self.button_y + self.button_scale_y - 100,
701                ),
702                text=(
703                    ''
704                    if (free_tries_remaining in [None, 0] or final_fee != 0)
705                    else ('' + str(free_tries_remaining))
706                ),
707                color=(0.6, 0.6, 0.6, 1),
708            )

Update for new incoming data.