bastd.ui.store.button

UI functionality for a button leading to the store.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""UI functionality for a button leading to the store."""
  4from __future__ import annotations
  5
  6from typing import TYPE_CHECKING
  7
  8import _ba
  9import ba
 10
 11if TYPE_CHECKING:
 12    from typing import Any, Sequence, Callable
 13
 14
 15class StoreButton:
 16    """A button leading to the store."""
 17
 18    def __init__(self,
 19                 parent: ba.Widget,
 20                 position: Sequence[float],
 21                 size: Sequence[float],
 22                 scale: float,
 23                 on_activate_call: Callable[[], Any] | None = None,
 24                 transition_delay: float | None = None,
 25                 color: Sequence[float] | None = None,
 26                 textcolor: Sequence[float] | None = None,
 27                 show_tickets: bool = False,
 28                 button_type: str | None = None,
 29                 sale_scale: float = 1.0):
 30        self._position = position
 31        self._size = size
 32        self._scale = scale
 33
 34        if on_activate_call is None:
 35            on_activate_call = ba.WeakCall(self._default_on_activate_call)
 36        self._on_activate_call = on_activate_call
 37
 38        self._button = ba.buttonwidget(
 39            parent=parent,
 40            size=size,
 41            label='' if show_tickets else ba.Lstr(resource='storeText'),
 42            scale=scale,
 43            autoselect=True,
 44            on_activate_call=self._on_activate,
 45            transition_delay=transition_delay,
 46            color=color,
 47            button_type=button_type)
 48
 49        self._title_text: ba.Widget | None
 50        self._ticket_text: ba.Widget | None
 51
 52        if show_tickets:
 53            self._title_text = ba.textwidget(
 54                parent=parent,
 55                position=(position[0] + size[0] * 0.5 * scale,
 56                          position[1] + size[1] * 0.65 * scale),
 57                size=(0, 0),
 58                h_align='center',
 59                v_align='center',
 60                maxwidth=size[0] * scale * 0.65,
 61                text=ba.Lstr(resource='storeText'),
 62                draw_controller=self._button,
 63                scale=scale,
 64                transition_delay=transition_delay,
 65                color=textcolor)
 66            self._ticket_text = ba.textwidget(
 67                parent=parent,
 68                size=(0, 0),
 69                h_align='center',
 70                v_align='center',
 71                maxwidth=size[0] * scale * 0.85,
 72                text='',
 73                color=(0.2, 1.0, 0.2),
 74                flatness=1.0,
 75                shadow=0.0,
 76                scale=scale * 0.6,
 77                transition_delay=transition_delay)
 78        else:
 79            self._title_text = None
 80            self._ticket_text = None
 81
 82        self._circle_rad = 12 * scale
 83        self._circle_center = (0.0, 0.0)
 84        self._sale_circle_center = (0.0, 0.0)
 85
 86        self._available_purchase_backing = ba.imagewidget(
 87            parent=parent,
 88            color=(1, 0, 0),
 89            draw_controller=self._button,
 90            size=(2.2 * self._circle_rad, 2.2 * self._circle_rad),
 91            texture=ba.gettexture('circleShadow'),
 92            transition_delay=transition_delay)
 93        self._available_purchase_text = ba.textwidget(
 94            parent=parent,
 95            size=(0, 0),
 96            h_align='center',
 97            v_align='center',
 98            text='',
 99            draw_controller=self._button,
100            color=(1, 1, 1),
101            flatness=1.0,
102            shadow=1.0,
103            scale=0.6 * scale,
104            maxwidth=self._circle_rad * 1.4,
105            transition_delay=transition_delay)
106
107        self._sale_circle_rad = 18 * scale * sale_scale
108        self._sale_backing = ba.imagewidget(
109            parent=parent,
110            color=(0.5, 0, 1.0),
111            draw_controller=self._button,
112            size=(2 * self._sale_circle_rad, 2 * self._sale_circle_rad),
113            texture=ba.gettexture('circleZigZag'),
114            transition_delay=transition_delay)
115        self._sale_title_text = ba.textwidget(
116            parent=parent,
117            size=(0, 0),
118            h_align='center',
119            v_align='center',
120            draw_controller=self._button,
121            color=(0, 1, 0),
122            flatness=1.0,
123            shadow=0.0,
124            scale=0.5 * scale * sale_scale,
125            maxwidth=self._sale_circle_rad * 1.5,
126            transition_delay=transition_delay)
127        self._sale_time_text = ba.textwidget(parent=parent,
128                                             size=(0, 0),
129                                             h_align='center',
130                                             v_align='center',
131                                             draw_controller=self._button,
132                                             color=(0, 1, 0),
133                                             flatness=1.0,
134                                             shadow=0.0,
135                                             scale=0.4 * scale * sale_scale,
136                                             maxwidth=self._sale_circle_rad *
137                                             1.5,
138                                             transition_delay=transition_delay)
139
140        self.set_position(position)
141        self._update_timer = ba.Timer(1.0,
142                                      ba.WeakCall(self._update),
143                                      repeat=True,
144                                      timetype=ba.TimeType.REAL)
145        self._update()
146
147    def _on_activate(self) -> None:
148        _ba.increment_analytics_count('Store button press')
149        self._on_activate_call()
150
151    def set_position(self, position: Sequence[float]) -> None:
152        """Set the button position."""
153        self._position = position
154        self._circle_center = (position[0] + 0.1 * self._size[0] * self._scale,
155                               position[1] + self._size[1] * self._scale * 0.8)
156        self._sale_circle_center = (position[0] +
157                                    0.07 * self._size[0] * self._scale,
158                                    position[1] +
159                                    self._size[1] * self._scale * 0.8)
160
161        if not self._button:
162            return
163        ba.buttonwidget(edit=self._button, position=self._position)
164        if self._title_text is not None:
165            ba.textwidget(edit=self._title_text,
166                          position=(self._position[0] +
167                                    self._size[0] * 0.5 * self._scale,
168                                    self._position[1] +
169                                    self._size[1] * 0.65 * self._scale))
170        if self._ticket_text is not None:
171            ba.textwidget(
172                edit=self._ticket_text,
173                position=(position[0] + self._size[0] * 0.5 * self._scale,
174                          position[1] + self._size[1] * 0.28 * self._scale),
175                size=(0, 0))
176        ba.imagewidget(
177            edit=self._available_purchase_backing,
178            position=(self._circle_center[0] - self._circle_rad * 1.02,
179                      self._circle_center[1] - self._circle_rad * 1.13))
180        ba.textwidget(edit=self._available_purchase_text,
181                      position=self._circle_center)
182
183        ba.imagewidget(
184            edit=self._sale_backing,
185            position=(self._sale_circle_center[0] - self._sale_circle_rad,
186                      self._sale_circle_center[1] - self._sale_circle_rad))
187        ba.textwidget(edit=self._sale_title_text,
188                      position=(self._sale_circle_center[0],
189                                self._sale_circle_center[1] +
190                                self._sale_circle_rad * 0.3))
191        ba.textwidget(edit=self._sale_time_text,
192                      position=(self._sale_circle_center[0],
193                                self._sale_circle_center[1] -
194                                self._sale_circle_rad * 0.3))
195
196    def _default_on_activate_call(self) -> None:
197        # pylint: disable=cyclic-import
198        from bastd.ui.account import show_sign_in_prompt
199        from bastd.ui.store.browser import StoreBrowserWindow
200        if _ba.get_v1_account_state() != 'signed_in':
201            show_sign_in_prompt()
202            return
203        StoreBrowserWindow(modal=True, origin_widget=self._button)
204
205    def get_button(self) -> ba.Widget:
206        """Return the underlying button widget."""
207        return self._button
208
209    def _update(self) -> None:
210        # pylint: disable=too-many-branches
211        # pylint: disable=cyclic-import
212        from ba import SpecialChar, TimeFormat
213        from ba.internal import (get_available_sale_time,
214                                 get_available_purchase_count)
215        if not self._button:
216            return  # Our instance may outlive our UI objects.
217
218        if self._ticket_text is not None:
219            if _ba.get_v1_account_state() == 'signed_in':
220                sval = ba.charstr(SpecialChar.TICKET) + str(
221                    _ba.get_v1_account_ticket_count())
222            else:
223                sval = '-'
224            ba.textwidget(edit=self._ticket_text, text=sval)
225        available_purchases = get_available_purchase_count()
226
227        # Old pro sale stuff..
228        sale_time = get_available_sale_time('extras')
229
230        # ..also look for new style sales.
231        if sale_time is None:
232            import datetime
233            sales_raw = _ba.get_v1_account_misc_read_val('sales', {})
234            sale_times = []
235            try:
236                # Look at the current set of sales; filter any with time
237                # remaining that we don't own.
238                for sale_item, sale_info in list(sales_raw.items()):
239                    if not _ba.get_purchased(sale_item):
240                        to_end = (datetime.datetime.utcfromtimestamp(
241                            sale_info['e']) -
242                                  datetime.datetime.utcnow()).total_seconds()
243                        if to_end > 0:
244                            sale_times.append(to_end)
245            except Exception:
246                ba.print_exception('Error parsing sales.')
247            if sale_times:
248                sale_time = int(min(sale_times) * 1000)
249
250        if sale_time is not None:
251            ba.textwidget(edit=self._sale_title_text,
252                          text=ba.Lstr(resource='store.saleText'))
253            ba.textwidget(edit=self._sale_time_text,
254                          text=ba.timestring(
255                              sale_time,
256                              centi=False,
257                              timeformat=TimeFormat.MILLISECONDS))
258            ba.imagewidget(edit=self._sale_backing, opacity=1.0)
259            ba.imagewidget(edit=self._available_purchase_backing, opacity=1.0)
260            ba.textwidget(edit=self._available_purchase_text, text='')
261            ba.imagewidget(edit=self._available_purchase_backing, opacity=0.0)
262        else:
263            ba.imagewidget(edit=self._sale_backing, opacity=0.0)
264            ba.textwidget(edit=self._sale_time_text, text='')
265            ba.textwidget(edit=self._sale_title_text, text='')
266            if available_purchases > 0:
267                ba.textwidget(edit=self._available_purchase_text,
268                              text=str(available_purchases))
269                ba.imagewidget(edit=self._available_purchase_backing,
270                               opacity=1.0)
271            else:
272                ba.textwidget(edit=self._available_purchase_text, text='')
273                ba.imagewidget(edit=self._available_purchase_backing,
274                               opacity=0.0)
class StoreButton:
 16class StoreButton:
 17    """A button leading to the store."""
 18
 19    def __init__(self,
 20                 parent: ba.Widget,
 21                 position: Sequence[float],
 22                 size: Sequence[float],
 23                 scale: float,
 24                 on_activate_call: Callable[[], Any] | None = None,
 25                 transition_delay: float | None = None,
 26                 color: Sequence[float] | None = None,
 27                 textcolor: Sequence[float] | None = None,
 28                 show_tickets: bool = False,
 29                 button_type: str | None = None,
 30                 sale_scale: float = 1.0):
 31        self._position = position
 32        self._size = size
 33        self._scale = scale
 34
 35        if on_activate_call is None:
 36            on_activate_call = ba.WeakCall(self._default_on_activate_call)
 37        self._on_activate_call = on_activate_call
 38
 39        self._button = ba.buttonwidget(
 40            parent=parent,
 41            size=size,
 42            label='' if show_tickets else ba.Lstr(resource='storeText'),
 43            scale=scale,
 44            autoselect=True,
 45            on_activate_call=self._on_activate,
 46            transition_delay=transition_delay,
 47            color=color,
 48            button_type=button_type)
 49
 50        self._title_text: ba.Widget | None
 51        self._ticket_text: ba.Widget | None
 52
 53        if show_tickets:
 54            self._title_text = ba.textwidget(
 55                parent=parent,
 56                position=(position[0] + size[0] * 0.5 * scale,
 57                          position[1] + size[1] * 0.65 * scale),
 58                size=(0, 0),
 59                h_align='center',
 60                v_align='center',
 61                maxwidth=size[0] * scale * 0.65,
 62                text=ba.Lstr(resource='storeText'),
 63                draw_controller=self._button,
 64                scale=scale,
 65                transition_delay=transition_delay,
 66                color=textcolor)
 67            self._ticket_text = ba.textwidget(
 68                parent=parent,
 69                size=(0, 0),
 70                h_align='center',
 71                v_align='center',
 72                maxwidth=size[0] * scale * 0.85,
 73                text='',
 74                color=(0.2, 1.0, 0.2),
 75                flatness=1.0,
 76                shadow=0.0,
 77                scale=scale * 0.6,
 78                transition_delay=transition_delay)
 79        else:
 80            self._title_text = None
 81            self._ticket_text = None
 82
 83        self._circle_rad = 12 * scale
 84        self._circle_center = (0.0, 0.0)
 85        self._sale_circle_center = (0.0, 0.0)
 86
 87        self._available_purchase_backing = ba.imagewidget(
 88            parent=parent,
 89            color=(1, 0, 0),
 90            draw_controller=self._button,
 91            size=(2.2 * self._circle_rad, 2.2 * self._circle_rad),
 92            texture=ba.gettexture('circleShadow'),
 93            transition_delay=transition_delay)
 94        self._available_purchase_text = ba.textwidget(
 95            parent=parent,
 96            size=(0, 0),
 97            h_align='center',
 98            v_align='center',
 99            text='',
100            draw_controller=self._button,
101            color=(1, 1, 1),
102            flatness=1.0,
103            shadow=1.0,
104            scale=0.6 * scale,
105            maxwidth=self._circle_rad * 1.4,
106            transition_delay=transition_delay)
107
108        self._sale_circle_rad = 18 * scale * sale_scale
109        self._sale_backing = ba.imagewidget(
110            parent=parent,
111            color=(0.5, 0, 1.0),
112            draw_controller=self._button,
113            size=(2 * self._sale_circle_rad, 2 * self._sale_circle_rad),
114            texture=ba.gettexture('circleZigZag'),
115            transition_delay=transition_delay)
116        self._sale_title_text = ba.textwidget(
117            parent=parent,
118            size=(0, 0),
119            h_align='center',
120            v_align='center',
121            draw_controller=self._button,
122            color=(0, 1, 0),
123            flatness=1.0,
124            shadow=0.0,
125            scale=0.5 * scale * sale_scale,
126            maxwidth=self._sale_circle_rad * 1.5,
127            transition_delay=transition_delay)
128        self._sale_time_text = ba.textwidget(parent=parent,
129                                             size=(0, 0),
130                                             h_align='center',
131                                             v_align='center',
132                                             draw_controller=self._button,
133                                             color=(0, 1, 0),
134                                             flatness=1.0,
135                                             shadow=0.0,
136                                             scale=0.4 * scale * sale_scale,
137                                             maxwidth=self._sale_circle_rad *
138                                             1.5,
139                                             transition_delay=transition_delay)
140
141        self.set_position(position)
142        self._update_timer = ba.Timer(1.0,
143                                      ba.WeakCall(self._update),
144                                      repeat=True,
145                                      timetype=ba.TimeType.REAL)
146        self._update()
147
148    def _on_activate(self) -> None:
149        _ba.increment_analytics_count('Store button press')
150        self._on_activate_call()
151
152    def set_position(self, position: Sequence[float]) -> None:
153        """Set the button position."""
154        self._position = position
155        self._circle_center = (position[0] + 0.1 * self._size[0] * self._scale,
156                               position[1] + self._size[1] * self._scale * 0.8)
157        self._sale_circle_center = (position[0] +
158                                    0.07 * self._size[0] * self._scale,
159                                    position[1] +
160                                    self._size[1] * self._scale * 0.8)
161
162        if not self._button:
163            return
164        ba.buttonwidget(edit=self._button, position=self._position)
165        if self._title_text is not None:
166            ba.textwidget(edit=self._title_text,
167                          position=(self._position[0] +
168                                    self._size[0] * 0.5 * self._scale,
169                                    self._position[1] +
170                                    self._size[1] * 0.65 * self._scale))
171        if self._ticket_text is not None:
172            ba.textwidget(
173                edit=self._ticket_text,
174                position=(position[0] + self._size[0] * 0.5 * self._scale,
175                          position[1] + self._size[1] * 0.28 * self._scale),
176                size=(0, 0))
177        ba.imagewidget(
178            edit=self._available_purchase_backing,
179            position=(self._circle_center[0] - self._circle_rad * 1.02,
180                      self._circle_center[1] - self._circle_rad * 1.13))
181        ba.textwidget(edit=self._available_purchase_text,
182                      position=self._circle_center)
183
184        ba.imagewidget(
185            edit=self._sale_backing,
186            position=(self._sale_circle_center[0] - self._sale_circle_rad,
187                      self._sale_circle_center[1] - self._sale_circle_rad))
188        ba.textwidget(edit=self._sale_title_text,
189                      position=(self._sale_circle_center[0],
190                                self._sale_circle_center[1] +
191                                self._sale_circle_rad * 0.3))
192        ba.textwidget(edit=self._sale_time_text,
193                      position=(self._sale_circle_center[0],
194                                self._sale_circle_center[1] -
195                                self._sale_circle_rad * 0.3))
196
197    def _default_on_activate_call(self) -> None:
198        # pylint: disable=cyclic-import
199        from bastd.ui.account import show_sign_in_prompt
200        from bastd.ui.store.browser import StoreBrowserWindow
201        if _ba.get_v1_account_state() != 'signed_in':
202            show_sign_in_prompt()
203            return
204        StoreBrowserWindow(modal=True, origin_widget=self._button)
205
206    def get_button(self) -> ba.Widget:
207        """Return the underlying button widget."""
208        return self._button
209
210    def _update(self) -> None:
211        # pylint: disable=too-many-branches
212        # pylint: disable=cyclic-import
213        from ba import SpecialChar, TimeFormat
214        from ba.internal import (get_available_sale_time,
215                                 get_available_purchase_count)
216        if not self._button:
217            return  # Our instance may outlive our UI objects.
218
219        if self._ticket_text is not None:
220            if _ba.get_v1_account_state() == 'signed_in':
221                sval = ba.charstr(SpecialChar.TICKET) + str(
222                    _ba.get_v1_account_ticket_count())
223            else:
224                sval = '-'
225            ba.textwidget(edit=self._ticket_text, text=sval)
226        available_purchases = get_available_purchase_count()
227
228        # Old pro sale stuff..
229        sale_time = get_available_sale_time('extras')
230
231        # ..also look for new style sales.
232        if sale_time is None:
233            import datetime
234            sales_raw = _ba.get_v1_account_misc_read_val('sales', {})
235            sale_times = []
236            try:
237                # Look at the current set of sales; filter any with time
238                # remaining that we don't own.
239                for sale_item, sale_info in list(sales_raw.items()):
240                    if not _ba.get_purchased(sale_item):
241                        to_end = (datetime.datetime.utcfromtimestamp(
242                            sale_info['e']) -
243                                  datetime.datetime.utcnow()).total_seconds()
244                        if to_end > 0:
245                            sale_times.append(to_end)
246            except Exception:
247                ba.print_exception('Error parsing sales.')
248            if sale_times:
249                sale_time = int(min(sale_times) * 1000)
250
251        if sale_time is not None:
252            ba.textwidget(edit=self._sale_title_text,
253                          text=ba.Lstr(resource='store.saleText'))
254            ba.textwidget(edit=self._sale_time_text,
255                          text=ba.timestring(
256                              sale_time,
257                              centi=False,
258                              timeformat=TimeFormat.MILLISECONDS))
259            ba.imagewidget(edit=self._sale_backing, opacity=1.0)
260            ba.imagewidget(edit=self._available_purchase_backing, opacity=1.0)
261            ba.textwidget(edit=self._available_purchase_text, text='')
262            ba.imagewidget(edit=self._available_purchase_backing, opacity=0.0)
263        else:
264            ba.imagewidget(edit=self._sale_backing, opacity=0.0)
265            ba.textwidget(edit=self._sale_time_text, text='')
266            ba.textwidget(edit=self._sale_title_text, text='')
267            if available_purchases > 0:
268                ba.textwidget(edit=self._available_purchase_text,
269                              text=str(available_purchases))
270                ba.imagewidget(edit=self._available_purchase_backing,
271                               opacity=1.0)
272            else:
273                ba.textwidget(edit=self._available_purchase_text, text='')
274                ba.imagewidget(edit=self._available_purchase_backing,
275                               opacity=0.0)

A button leading to the store.

StoreButton( parent: _ba.Widget, position: Sequence[float], size: Sequence[float], scale: float, on_activate_call: Optional[Callable[[], Any]] = None, transition_delay: float | None = None, color: Optional[Sequence[float]] = None, textcolor: Optional[Sequence[float]] = None, show_tickets: bool = False, button_type: str | None = None, sale_scale: float = 1.0)
 19    def __init__(self,
 20                 parent: ba.Widget,
 21                 position: Sequence[float],
 22                 size: Sequence[float],
 23                 scale: float,
 24                 on_activate_call: Callable[[], Any] | None = None,
 25                 transition_delay: float | None = None,
 26                 color: Sequence[float] | None = None,
 27                 textcolor: Sequence[float] | None = None,
 28                 show_tickets: bool = False,
 29                 button_type: str | None = None,
 30                 sale_scale: float = 1.0):
 31        self._position = position
 32        self._size = size
 33        self._scale = scale
 34
 35        if on_activate_call is None:
 36            on_activate_call = ba.WeakCall(self._default_on_activate_call)
 37        self._on_activate_call = on_activate_call
 38
 39        self._button = ba.buttonwidget(
 40            parent=parent,
 41            size=size,
 42            label='' if show_tickets else ba.Lstr(resource='storeText'),
 43            scale=scale,
 44            autoselect=True,
 45            on_activate_call=self._on_activate,
 46            transition_delay=transition_delay,
 47            color=color,
 48            button_type=button_type)
 49
 50        self._title_text: ba.Widget | None
 51        self._ticket_text: ba.Widget | None
 52
 53        if show_tickets:
 54            self._title_text = ba.textwidget(
 55                parent=parent,
 56                position=(position[0] + size[0] * 0.5 * scale,
 57                          position[1] + size[1] * 0.65 * scale),
 58                size=(0, 0),
 59                h_align='center',
 60                v_align='center',
 61                maxwidth=size[0] * scale * 0.65,
 62                text=ba.Lstr(resource='storeText'),
 63                draw_controller=self._button,
 64                scale=scale,
 65                transition_delay=transition_delay,
 66                color=textcolor)
 67            self._ticket_text = ba.textwidget(
 68                parent=parent,
 69                size=(0, 0),
 70                h_align='center',
 71                v_align='center',
 72                maxwidth=size[0] * scale * 0.85,
 73                text='',
 74                color=(0.2, 1.0, 0.2),
 75                flatness=1.0,
 76                shadow=0.0,
 77                scale=scale * 0.6,
 78                transition_delay=transition_delay)
 79        else:
 80            self._title_text = None
 81            self._ticket_text = None
 82
 83        self._circle_rad = 12 * scale
 84        self._circle_center = (0.0, 0.0)
 85        self._sale_circle_center = (0.0, 0.0)
 86
 87        self._available_purchase_backing = ba.imagewidget(
 88            parent=parent,
 89            color=(1, 0, 0),
 90            draw_controller=self._button,
 91            size=(2.2 * self._circle_rad, 2.2 * self._circle_rad),
 92            texture=ba.gettexture('circleShadow'),
 93            transition_delay=transition_delay)
 94        self._available_purchase_text = ba.textwidget(
 95            parent=parent,
 96            size=(0, 0),
 97            h_align='center',
 98            v_align='center',
 99            text='',
100            draw_controller=self._button,
101            color=(1, 1, 1),
102            flatness=1.0,
103            shadow=1.0,
104            scale=0.6 * scale,
105            maxwidth=self._circle_rad * 1.4,
106            transition_delay=transition_delay)
107
108        self._sale_circle_rad = 18 * scale * sale_scale
109        self._sale_backing = ba.imagewidget(
110            parent=parent,
111            color=(0.5, 0, 1.0),
112            draw_controller=self._button,
113            size=(2 * self._sale_circle_rad, 2 * self._sale_circle_rad),
114            texture=ba.gettexture('circleZigZag'),
115            transition_delay=transition_delay)
116        self._sale_title_text = ba.textwidget(
117            parent=parent,
118            size=(0, 0),
119            h_align='center',
120            v_align='center',
121            draw_controller=self._button,
122            color=(0, 1, 0),
123            flatness=1.0,
124            shadow=0.0,
125            scale=0.5 * scale * sale_scale,
126            maxwidth=self._sale_circle_rad * 1.5,
127            transition_delay=transition_delay)
128        self._sale_time_text = ba.textwidget(parent=parent,
129                                             size=(0, 0),
130                                             h_align='center',
131                                             v_align='center',
132                                             draw_controller=self._button,
133                                             color=(0, 1, 0),
134                                             flatness=1.0,
135                                             shadow=0.0,
136                                             scale=0.4 * scale * sale_scale,
137                                             maxwidth=self._sale_circle_rad *
138                                             1.5,
139                                             transition_delay=transition_delay)
140
141        self.set_position(position)
142        self._update_timer = ba.Timer(1.0,
143                                      ba.WeakCall(self._update),
144                                      repeat=True,
145                                      timetype=ba.TimeType.REAL)
146        self._update()
def set_position(self, position: Sequence[float]) -> None:
152    def set_position(self, position: Sequence[float]) -> None:
153        """Set the button position."""
154        self._position = position
155        self._circle_center = (position[0] + 0.1 * self._size[0] * self._scale,
156                               position[1] + self._size[1] * self._scale * 0.8)
157        self._sale_circle_center = (position[0] +
158                                    0.07 * self._size[0] * self._scale,
159                                    position[1] +
160                                    self._size[1] * self._scale * 0.8)
161
162        if not self._button:
163            return
164        ba.buttonwidget(edit=self._button, position=self._position)
165        if self._title_text is not None:
166            ba.textwidget(edit=self._title_text,
167                          position=(self._position[0] +
168                                    self._size[0] * 0.5 * self._scale,
169                                    self._position[1] +
170                                    self._size[1] * 0.65 * self._scale))
171        if self._ticket_text is not None:
172            ba.textwidget(
173                edit=self._ticket_text,
174                position=(position[0] + self._size[0] * 0.5 * self._scale,
175                          position[1] + self._size[1] * 0.28 * self._scale),
176                size=(0, 0))
177        ba.imagewidget(
178            edit=self._available_purchase_backing,
179            position=(self._circle_center[0] - self._circle_rad * 1.02,
180                      self._circle_center[1] - self._circle_rad * 1.13))
181        ba.textwidget(edit=self._available_purchase_text,
182                      position=self._circle_center)
183
184        ba.imagewidget(
185            edit=self._sale_backing,
186            position=(self._sale_circle_center[0] - self._sale_circle_rad,
187                      self._sale_circle_center[1] - self._sale_circle_rad))
188        ba.textwidget(edit=self._sale_title_text,
189                      position=(self._sale_circle_center[0],
190                                self._sale_circle_center[1] +
191                                self._sale_circle_rad * 0.3))
192        ba.textwidget(edit=self._sale_time_text,
193                      position=(self._sale_circle_center[0],
194                                self._sale_circle_center[1] -
195                                self._sale_circle_rad * 0.3))

Set the button position.

def get_button(self) -> _ba.Widget:
206    def get_button(self) -> ba.Widget:
207        """Return the underlying button widget."""
208        return self._button

Return the underlying button widget.