bauiv1lib.store.item

UI functionality related to UI items.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""UI functionality related to UI items."""
  4from __future__ import annotations
  5
  6from typing import TYPE_CHECKING
  7
  8import bascenev1 as bs
  9import bauiv1 as bui
 10
 11if TYPE_CHECKING:
 12    from typing import Any
 13
 14
 15def instantiate_store_item_display(
 16    item_name: str,
 17    item: dict[str, Any],
 18    parent_widget: bui.Widget,
 19    b_pos: tuple[float, float],
 20    b_width: float,
 21    b_height: float,
 22    *,
 23    boffs_h: float = 0.0,
 24    boffs_h2: float = 0.0,
 25    boffs_v2: float = 0,
 26    delay: float = 0.0,
 27    button: bool = True,
 28) -> None:
 29    """(internal)"""
 30    # pylint: disable=too-many-positional-arguments
 31    # pylint: disable=too-many-statements
 32    # pylint: disable=too-many-branches
 33    # pylint: disable=too-many-locals
 34    assert bui.app.classic is not None
 35    store = bui.app.classic.store
 36
 37    plus = bui.app.plus
 38    assert plus is not None
 39
 40    del boffs_h  # unused arg
 41    del boffs_h2  # unused arg
 42    del boffs_v2  # unused arg
 43    item_info = store.get_store_item(item_name)
 44    title_v = 0.24
 45    price_v = 0.145
 46    base_text_scale = 1.0
 47
 48    item['name'] = title = store.get_store_item_name_translated(item_name)
 49
 50    btn: bui.Widget | None
 51
 52    # Hack; showbuffer stuff isn't working well when we're showing merch.
 53    showbuffer = 10 if item_name in {'merch', 'pro', 'pro_sale'} else 76.0
 54
 55    if button:
 56        item['button'] = btn = bui.buttonwidget(
 57            parent=parent_widget,
 58            position=b_pos,
 59            transition_delay=delay,
 60            show_buffer_top=showbuffer,
 61            enable_sound=False,
 62            button_type='square',
 63            size=(b_width, b_height),
 64            autoselect=True,
 65            label='',
 66        )
 67        bui.widget(edit=btn, show_buffer_bottom=showbuffer)
 68    else:
 69        btn = None
 70
 71    b_offs_x = -0.015 * b_width
 72    check_pos = 0.76
 73
 74    icon_tex = None
 75    tint_tex = None
 76    tint_color = None
 77    tint2_color = None
 78    tex_name: str | None = None
 79    desc: bui.Lstr | None = None
 80    modes: bui.Lstr | None = None
 81
 82    if item_name.startswith('characters.'):
 83        assert bui.app.classic is not None
 84        character = bui.app.classic.spaz_appearances[item_info['character']]
 85        tint_color = (
 86            item_info['color']
 87            if 'color' in item_info
 88            else (
 89                character.default_color
 90                if character.default_color is not None
 91                else (1, 1, 1)
 92            )
 93        )
 94        tint2_color = (
 95            item_info['highlight']
 96            if 'highlight' in item_info
 97            else (
 98                character.default_highlight
 99                if character.default_highlight is not None
100                else (1, 1, 1)
101            )
102        )
103        icon_tex = character.icon_texture
104        tint_tex = character.icon_mask_texture
105        title_v = 0.255
106        price_v = 0.145
107    elif item_name == 'merch':
108        base_text_scale = 0.6
109        title_v = 0.85
110        price_v = 0.15
111    elif item_name in ['upgrades.pro', 'pro']:
112        base_text_scale = 0.6
113        title_v = 0.85
114        price_v = 0.15
115    elif item_name.startswith('maps.'):
116        map_type = item_info['map_type']
117        tex_name = map_type.get_preview_texture_name()
118        title_v = 0.312
119        price_v = 0.17
120
121    elif item_name.startswith('games.'):
122        gametype = item_info['gametype']
123        modes_l = []
124        if gametype.supports_session_type(bs.CoopSession):
125            modes_l.append(bui.Lstr(resource='playModes.coopText'))
126        if gametype.supports_session_type(bs.DualTeamSession):
127            modes_l.append(bui.Lstr(resource='playModes.teamsText'))
128        if gametype.supports_session_type(bs.FreeForAllSession):
129            modes_l.append(bui.Lstr(resource='playModes.freeForAllText'))
130
131        if len(modes_l) == 3:
132            modes = bui.Lstr(
133                value='${A}, ${B}, ${C}',
134                subs=[
135                    ('${A}', modes_l[0]),
136                    ('${B}', modes_l[1]),
137                    ('${C}', modes_l[2]),
138                ],
139            )
140        elif len(modes_l) == 2:
141            modes = bui.Lstr(
142                value='${A}, ${B}',
143                subs=[('${A}', modes_l[0]), ('${B}', modes_l[1])],
144            )
145        elif len(modes_l) == 1:
146            modes = modes_l[0]
147        else:
148            raise RuntimeError()
149        desc = gametype.get_description_display_string(bs.CoopSession)
150        tex_name = item_info['previewTex']
151        base_text_scale = 0.8
152        title_v = 0.48
153        price_v = 0.17
154    elif item_name == 'upgrades.infinite_runaround':
155        base_text_scale = 0.8
156        desc = bui.Lstr(
157            translate=(
158                'gameDescriptions',
159                'Prevent enemies from reaching the exit.',
160            )
161        )
162        modes = bui.Lstr(resource='playModes.coopText')
163        tex_name = 'towerDPreview'
164        title_v = 0.48
165        price_v = 0.17
166    elif item_name == 'upgrades.infinite_onslaught':
167        base_text_scale = 0.8
168        desc = bui.Lstr(
169            translate=(
170                'gameDescriptions',
171                'Defeat all enemies.',
172            )
173        )
174        modes = bui.Lstr(resource='playModes.coopText')
175        tex_name = 'doomShroomPreview'
176        title_v = 0.48
177        price_v = 0.17
178
179    elif item_name.startswith('icons.'):
180        base_text_scale = 1.5
181        price_v = 0.2
182        check_pos = 0.6
183
184    if item_name.startswith('characters.'):
185        frame_size = b_width * 0.7
186        im_dim = frame_size * (100.0 / 113.0)
187        im_pos = (
188            b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x,
189            b_pos[1] + b_height * 0.57 - im_dim * 0.5,
190        )
191        mask_texture = bui.gettexture('characterIconMask')
192        assert icon_tex is not None
193        assert tint_tex is not None
194        bui.imagewidget(
195            parent=parent_widget,
196            position=im_pos,
197            size=(im_dim, im_dim),
198            color=(1, 1, 1),
199            transition_delay=delay,
200            mask_texture=mask_texture,
201            draw_controller=btn,
202            texture=bui.gettexture(icon_tex),
203            tint_texture=bui.gettexture(tint_tex),
204            tint_color=tint_color,
205            tint2_color=tint2_color,
206        )
207
208    if item_name == 'merch':
209        frame_size = b_width * 0.65
210        im_dim = frame_size * (100.0 / 113.0)
211        im_pos = (
212            b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x,
213            b_pos[1] + b_height * 0.47 - im_dim * 0.5,
214        )
215        bui.imagewidget(
216            parent=parent_widget,
217            position=im_pos,
218            size=(im_dim, im_dim),
219            transition_delay=delay,
220            draw_controller=btn,
221            opacity=1.0,
222            texture=bui.gettexture('merch'),
223        )
224
225    if item_name in ['pro', 'upgrades.pro']:
226        frame_size = b_width * 0.5
227        im_dim = frame_size * (100.0 / 113.0)
228        im_pos = (
229            b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x,
230            b_pos[1] + b_height * 0.5 - im_dim * 0.5,
231        )
232        bui.imagewidget(
233            parent=parent_widget,
234            position=im_pos,
235            size=(im_dim, im_dim),
236            transition_delay=delay,
237            draw_controller=btn,
238            color=(0.3, 0.0, 0.3),
239            opacity=0.3,
240            texture=bui.gettexture('logo'),
241        )
242        txt = bui.Lstr(resource='store.bombSquadProNewDescriptionText')
243
244        item['descriptionText'] = bui.textwidget(
245            parent=parent_widget,
246            text=txt,
247            position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.69),
248            transition_delay=delay,
249            scale=b_width * (1.0 / 230.0) * base_text_scale * 0.75,
250            maxwidth=b_width * 0.75,
251            max_height=b_height * 0.2,
252            size=(0, 0),
253            h_align='center',
254            v_align='center',
255            draw_controller=btn,
256            color=(0.3, 1, 0.3),
257        )
258
259        extra_backings = item['extra_backings'] = []
260        extra_images = item['extra_images'] = []
261        extra_texts = item['extra_texts'] = []
262        extra_texts_2 = item['extra_texts_2'] = []
263
264        backing_color = (0.5, 0.8, 0.3) if button else (0.6, 0.5, 0.65)
265        b_square_texture = bui.gettexture('buttonSquare')
266        char_mask_texture = bui.gettexture('characterIconMask')
267
268        pos = (0.17, 0.43)
269        tile_size = (b_width * 0.16 * 1.2, b_width * 0.2 * 1.2)
270        tile_pos = (b_pos[0] + b_width * pos[0], b_pos[1] + b_height * pos[1])
271        extra_backings.append(
272            bui.imagewidget(
273                parent=parent_widget,
274                position=(
275                    tile_pos[0] - tile_size[0] * 0.5,
276                    tile_pos[1] - tile_size[1] * 0.5,
277                ),
278                size=tile_size,
279                transition_delay=delay,
280                draw_controller=btn,
281                color=backing_color,
282                texture=b_square_texture,
283            )
284        )
285        im_size = tile_size[0] * 0.8
286        extra_images.append(
287            bui.imagewidget(
288                parent=parent_widget,
289                position=(
290                    tile_pos[0] - im_size * 0.5,
291                    tile_pos[1] - im_size * 0.4,
292                ),
293                size=(im_size, im_size),
294                transition_delay=delay,
295                draw_controller=btn,
296                color=(1, 1, 1),
297                texture=bui.gettexture('ticketsMore'),
298            )
299        )
300        bonus_tickets = str(
301            plus.get_v1_account_misc_read_val('proBonusTickets', 100)
302        )
303        extra_texts.append(
304            bui.textwidget(
305                parent=parent_widget,
306                draw_controller=btn,
307                position=(
308                    tile_pos[0] - tile_size[0] * 0.03,
309                    tile_pos[1] - tile_size[1] * 0.25,
310                ),
311                size=(0, 0),
312                color=(0.6, 1, 0.6),
313                transition_delay=delay,
314                h_align='center',
315                v_align='center',
316                maxwidth=tile_size[0] * 0.7,
317                scale=0.55,
318                text=bui.Lstr(
319                    resource='getTicketsWindow.ticketsText',
320                    subs=[('${COUNT}', bonus_tickets)],
321                ),
322                flatness=1.0,
323                shadow=0.0,
324            )
325        )
326
327        for charname, pos in [
328            ('Kronk', (0.32, 0.45)),
329            ('Zoe', (0.425, 0.4)),
330            ('Jack Morgan', (0.555, 0.45)),
331            ('Mel', (0.645, 0.4)),
332        ]:
333            tile_size = (b_width * 0.16 * 0.9, b_width * 0.2 * 0.9)
334            tile_pos = (
335                b_pos[0] + b_width * pos[0],
336                b_pos[1] + b_height * pos[1],
337            )
338            assert bui.app.classic is not None
339            character = bui.app.classic.spaz_appearances[charname]
340            extra_backings.append(
341                bui.imagewidget(
342                    parent=parent_widget,
343                    position=(
344                        tile_pos[0] - tile_size[0] * 0.5,
345                        tile_pos[1] - tile_size[1] * 0.5,
346                    ),
347                    size=tile_size,
348                    transition_delay=delay,
349                    draw_controller=btn,
350                    color=backing_color,
351                    texture=b_square_texture,
352                )
353            )
354            im_size = tile_size[0] * 0.7
355            extra_images.append(
356                bui.imagewidget(
357                    parent=parent_widget,
358                    position=(
359                        tile_pos[0] - im_size * 0.53,
360                        tile_pos[1] - im_size * 0.35,
361                    ),
362                    size=(im_size, im_size),
363                    transition_delay=delay,
364                    draw_controller=btn,
365                    color=(1, 1, 1),
366                    texture=bui.gettexture(character.icon_texture),
367                    tint_texture=bui.gettexture(character.icon_mask_texture),
368                    tint_color=character.default_color,
369                    tint2_color=character.default_highlight,
370                    mask_texture=char_mask_texture,
371                )
372            )
373            extra_texts.append(
374                bui.textwidget(
375                    parent=parent_widget,
376                    draw_controller=btn,
377                    position=(
378                        tile_pos[0] - im_size * 0.03,
379                        tile_pos[1] - im_size * 0.51,
380                    ),
381                    size=(0, 0),
382                    color=(0.6, 1, 0.6),
383                    transition_delay=delay,
384                    h_align='center',
385                    v_align='center',
386                    maxwidth=tile_size[0] * 0.7,
387                    scale=0.55,
388                    text=bui.Lstr(translate=('characterNames', charname)),
389                    flatness=1.0,
390                    shadow=0.0,
391                )
392            )
393
394        # If we have a 'total-worth' item-id for this id, show that price so
395        # the user knows how much this is worth.
396        total_worth_item = plus.get_v1_account_misc_read_val('twrths', {}).get(
397            item_name
398        )
399        total_worth_price: str | None
400        if total_worth_item is not None:
401            price = plus.get_price(total_worth_item)
402            total_worth_price = (
403                store.get_clean_price(price) if price is not None else '??'
404            )
405        else:
406            total_worth_price = None
407
408        if total_worth_price is not None:
409            total_worth_text = bui.Lstr(
410                resource='store.totalWorthText',
411                subs=[('${TOTAL_WORTH}', total_worth_price)],
412            )
413            extra_texts_2.append(
414                bui.textwidget(
415                    parent=parent_widget,
416                    text=total_worth_text,
417                    position=(
418                        b_pos[0] + b_width * 0.5 + b_offs_x,
419                        b_pos[1] + b_height * 0.25,
420                    ),
421                    transition_delay=delay,
422                    scale=b_width * (1.0 / 230.0) * base_text_scale * 0.45,
423                    maxwidth=b_width * 0.5,
424                    size=(0, 0),
425                    h_align='center',
426                    v_align='center',
427                    shadow=1.0,
428                    flatness=1.0,
429                    draw_controller=btn,
430                    color=(0.3, 1, 1),
431                )
432            )
433
434        mesh_opaque = bui.getmesh('level_select_button_opaque')
435        mesh_transparent = bui.getmesh('level_select_button_transparent')
436        mask_tex = bui.gettexture('mapPreviewMask')
437        for levelname, preview_tex_name, pos in [
438            ('Infinite Onslaught', 'doomShroomPreview', (0.80, 0.48)),
439            ('Infinite Runaround', 'towerDPreview', (0.80, 0.32)),
440        ]:
441            tile_size = (b_width * 0.2, b_width * 0.13)
442            tile_pos = (
443                b_pos[0] + b_width * pos[0],
444                b_pos[1] + b_height * pos[1],
445            )
446            im_size = tile_size[0] * 0.8
447            extra_backings.append(
448                bui.imagewidget(
449                    parent=parent_widget,
450                    position=(
451                        tile_pos[0] - tile_size[0] * 0.5,
452                        tile_pos[1] - tile_size[1] * 0.5,
453                    ),
454                    size=tile_size,
455                    transition_delay=delay,
456                    draw_controller=btn,
457                    color=backing_color,
458                    texture=b_square_texture,
459                )
460            )
461
462            # Hack - gotta draw two transparent versions to avoid z issues.
463            for mod in mesh_opaque, mesh_transparent:
464                extra_images.append(
465                    bui.imagewidget(
466                        parent=parent_widget,
467                        position=(
468                            tile_pos[0] - im_size * 0.52,
469                            tile_pos[1] - im_size * 0.2,
470                        ),
471                        size=(im_size, im_size * 0.5),
472                        transition_delay=delay,
473                        mesh_transparent=mod,
474                        mask_texture=mask_tex,
475                        draw_controller=btn,
476                        texture=bui.gettexture(preview_tex_name),
477                    )
478                )
479
480            extra_texts.append(
481                bui.textwidget(
482                    parent=parent_widget,
483                    draw_controller=btn,
484                    position=(
485                        tile_pos[0] - im_size * 0.03,
486                        tile_pos[1] - im_size * 0.2,
487                    ),
488                    size=(0, 0),
489                    color=(0.6, 1, 0.6),
490                    transition_delay=delay,
491                    h_align='center',
492                    v_align='center',
493                    maxwidth=tile_size[0] * 0.7,
494                    scale=0.55,
495                    text=bui.Lstr(translate=('coopLevelNames', levelname)),
496                    flatness=1.0,
497                    shadow=0.0,
498                )
499            )
500
501    if item_name.startswith('icons.'):
502        item['icon_text'] = bui.textwidget(
503            parent=parent_widget,
504            text=item_info['icon'],
505            position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.5),
506            transition_delay=delay,
507            scale=b_width * (1.0 / 230.0) * base_text_scale * 2.0,
508            maxwidth=b_width * 0.9,
509            max_height=b_height * 0.9,
510            size=(0, 0),
511            h_align='center',
512            v_align='center',
513            draw_controller=btn,
514        )
515
516    if item_name.startswith('maps.'):
517        frame_size = b_width * 0.9
518        im_dim = frame_size * (100.0 / 113.0)
519        im_pos = (
520            b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x,
521            b_pos[1] + b_height * 0.62 - im_dim * 0.25,
522        )
523        mesh_opaque = bui.getmesh('level_select_button_opaque')
524        mesh_transparent = bui.getmesh('level_select_button_transparent')
525        mask_tex = bui.gettexture('mapPreviewMask')
526        assert tex_name is not None
527        bui.imagewidget(
528            parent=parent_widget,
529            position=im_pos,
530            size=(im_dim, im_dim * 0.5),
531            transition_delay=delay,
532            mesh_opaque=mesh_opaque,
533            mesh_transparent=mesh_transparent,
534            mask_texture=mask_tex,
535            draw_controller=btn,
536            texture=bui.gettexture(tex_name),
537        )
538
539    if item_name.startswith('games.') or item_name in (
540        'upgrades.infinite_runaround',
541        'upgrades.infinite_onslaught',
542    ):
543        frame_size = b_width * 0.8
544        im_dim = frame_size * (100.0 / 113.0)
545        im_pos = (
546            b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x,
547            b_pos[1] + b_height * 0.72 - im_dim * 0.25,
548        )
549        mesh_opaque = bui.getmesh('level_select_button_opaque')
550        mesh_transparent = bui.getmesh('level_select_button_transparent')
551        mask_tex = bui.gettexture('mapPreviewMask')
552        assert tex_name is not None
553        bui.imagewidget(
554            parent=parent_widget,
555            position=im_pos,
556            size=(im_dim, im_dim * 0.5),
557            transition_delay=delay,
558            mesh_opaque=mesh_opaque,
559            mesh_transparent=mesh_transparent,
560            mask_texture=mask_tex,
561            draw_controller=btn,
562            texture=bui.gettexture(tex_name),
563        )
564        item['descriptionText'] = bui.textwidget(
565            parent=parent_widget,
566            text=desc,
567            position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.36),
568            transition_delay=delay,
569            scale=b_width * (1.0 / 230.0) * base_text_scale * 0.78,
570            maxwidth=b_width * 0.8,
571            max_height=b_height * 0.14,
572            size=(0, 0),
573            h_align='center',
574            v_align='center',
575            draw_controller=btn,
576            flatness=1.0,
577            shadow=0.0,
578            color=(0.6, 1, 0.6),
579        )
580        item['gameModesText'] = bui.textwidget(
581            parent=parent_widget,
582            text=modes,
583            position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.26),
584            transition_delay=delay,
585            scale=b_width * (1.0 / 230.0) * base_text_scale * 0.65,
586            maxwidth=b_width * 0.8,
587            size=(0, 0),
588            h_align='center',
589            v_align='center',
590            draw_controller=btn,
591            shadow=0,
592            flatness=1.0,
593            color=(0.6, 0.8, 0.6),
594        )
595
596    if not item_name.startswith('icons.'):
597        item['title_text'] = bui.textwidget(
598            parent=parent_widget,
599            text=title,
600            position=(
601                b_pos[0] + b_width * 0.5 + b_offs_x,
602                b_pos[1] + b_height * title_v,
603            ),
604            transition_delay=delay,
605            scale=b_width * (1.0 / 230.0) * base_text_scale,
606            maxwidth=b_width * 0.8,
607            size=(0, 0),
608            h_align='center',
609            v_align='center',
610            draw_controller=btn,
611            color=(0.7, 0.9, 0.7, 1.0),
612        )
613
614    item['purchase_check'] = bui.imagewidget(
615        parent=parent_widget,
616        position=(b_pos[0] + b_width * check_pos, b_pos[1] + b_height * 0.05),
617        transition_delay=delay,
618        mesh_transparent=bui.getmesh('checkTransparent'),
619        opacity=0.0,
620        size=(60, 60),
621        color=(0.6, 0.5, 0.8),
622        draw_controller=btn,
623        texture=bui.gettexture('uiAtlas'),
624    )
625    item['price_widget'] = bui.textwidget(
626        parent=parent_widget,
627        text='',
628        position=(
629            b_pos[0] + b_width * 0.5 + b_offs_x,
630            b_pos[1] + b_height * price_v,
631        ),
632        transition_delay=delay,
633        scale=b_width * (1.0 / 300.0) * base_text_scale,
634        maxwidth=b_width * 0.9,
635        size=(0, 0),
636        h_align='center',
637        v_align='center',
638        draw_controller=btn,
639        color=(0.2, 1, 0.2, 1.0),
640    )
641    item['price_widget_left'] = bui.textwidget(
642        parent=parent_widget,
643        text='',
644        position=(
645            b_pos[0] + b_width * 0.33 + b_offs_x,
646            b_pos[1] + b_height * price_v,
647        ),
648        transition_delay=delay,
649        scale=b_width * (1.0 / 300.0) * base_text_scale,
650        maxwidth=b_width * 0.3,
651        size=(0, 0),
652        h_align='center',
653        v_align='center',
654        draw_controller=btn,
655        color=(0.2, 1, 0.2, 0.5),
656    )
657    item['price_widget_right'] = bui.textwidget(
658        parent=parent_widget,
659        text='',
660        position=(
661            b_pos[0] + b_width * 0.66 + b_offs_x,
662            b_pos[1] + b_height * price_v,
663        ),
664        transition_delay=delay,
665        scale=1.1 * b_width * (1.0 / 300.0) * base_text_scale,
666        maxwidth=b_width * 0.3,
667        size=(0, 0),
668        h_align='center',
669        v_align='center',
670        draw_controller=btn,
671        color=(0.2, 1, 0.2, 1.0),
672    )
673    item['price_slash_widget'] = bui.imagewidget(
674        parent=parent_widget,
675        position=(
676            b_pos[0] + b_width * 0.33 + b_offs_x - 36,
677            b_pos[1] + b_height * price_v - 35,
678        ),
679        transition_delay=delay,
680        texture=bui.gettexture('slash'),
681        opacity=0.0,
682        size=(70, 70),
683        draw_controller=btn,
684        color=(1, 0, 0),
685    )
686    badge_rad = 44
687    badge_center = (
688        b_pos[0] + b_width * 0.1 + b_offs_x,
689        b_pos[1] + b_height * 0.87,
690    )
691    item['sale_bg_widget'] = bui.imagewidget(
692        parent=parent_widget,
693        position=(badge_center[0] - badge_rad, badge_center[1] - badge_rad),
694        opacity=0.0,
695        transition_delay=delay,
696        texture=bui.gettexture('circleZigZag'),
697        draw_controller=btn,
698        size=(badge_rad * 2, badge_rad * 2),
699        color=(0.5, 0, 1),
700    )
701    item['sale_title_widget'] = bui.textwidget(
702        parent=parent_widget,
703        position=(badge_center[0], badge_center[1] + 12),
704        transition_delay=delay,
705        scale=1.0,
706        maxwidth=badge_rad * 1.6,
707        size=(0, 0),
708        h_align='center',
709        v_align='center',
710        draw_controller=btn,
711        shadow=0.0,
712        flatness=1.0,
713        color=(0, 1, 0),
714    )
715    item['sale_time_widget'] = bui.textwidget(
716        parent=parent_widget,
717        position=(badge_center[0], badge_center[1] - 12),
718        transition_delay=delay,
719        scale=0.7,
720        maxwidth=badge_rad * 1.6,
721        size=(0, 0),
722        h_align='center',
723        v_align='center',
724        draw_controller=btn,
725        shadow=0.0,
726        flatness=1.0,
727        color=(0.0, 1, 0.0, 1),
728    )