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=f'{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=f'{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=f'{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            glow_type='uniform',
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=f'{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=f'{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=f'{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            )
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=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            )

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=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        )
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:
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            )

Update for new incoming data.