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

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

Update for new incoming data.