# Path: tft/driver/ugui.py
# class Touchable(NoTouch):
#     def __init__(self, location, font, height, width, fgcolor, bgcolor, fontcolor, border, can_drag, value, initial_value):
#         super().__init__(location, font, height, width, fgcolor, bgcolor, fontcolor, border, value, initial_value)
#         self.can_drag = can_drag
#         self.busy = False
#         self.was_touched = False
# 
#     def _set_callbacks(self, cb, args, cb_end=None, cbe_args=None):
#         self.callback = cb
#         self.args = args
#         if cb_end is not None:
#             self.cb_end = cb_end
#             self.cbe_args = cbe_args
# 
#     def greyed_out(self, val=None):
#         if val is not None and self._greyed_out != val:
#             self._greyed_out = val
#             self.draw_border()
#             self.redraw = True
#             self.show_if_current()
#         return self._greyed_out
# 
#     def _trytouch(self, x, y): # If touched in bounding box, process it otherwise do nothing
#         x0 = self.location[0]
#         x1 = self.location[0] + self.width
#         y0 = self.location[1]
#         y1 = self.location[1] + self.height
#         if x0 <= x <= x1 and y0 <= y <= y1:
#             self.was_touched = True
#             if not self.busy or self.can_drag:
#                 self._touched(x, y) # Called repeatedly for draggable objects
#                 self.busy = True # otherwise once only
# 
#     def _untouched(self): # Default if not defined in subclass
#         self.cb_end(self, *self.cbe_args) # Callback not a bound method so pass self
# 
# def dolittle(*_):
#     pass
# 
# def print_centered(tft, x, y, s, color, font, clip=False, scroll=False):
#     old_style = tft.getTextStyle()
#     length, height = get_stringsize(s, font)
#     tft.setTextStyle(color, None, 2, font)
#     tft.setTextPos(max(x - length // 2, 0), max(y - height // 2, 0), clip, scroll)
#     tft.printString(s)
#     tft.setTextStyle(*old_style)
# 
# Path: tft/primitives/delay_ms.py
# class Delay_ms:
#     verbose = False  # verbose and can_alloc retained to avoid breaking code.
#     def __init__(self, func=None, args=(), can_alloc=True, duration=1000):
#         self._func = func
#         self._args = args
#         self._duration = duration  # Default duration
#         self._tstop = None  # Stop time (ms). None signifies not running.
#         self._tsave = None  # Temporary storage for stop time
#         self._ktask = None  # timer task
#         self._retrn = None  # Return value of launched callable
#         self._do_trig = self._trig  # Avoid allocation in .trigger
# 
#     def stop(self):
#         if self._ktask is not None:
#             self._ktask.cancel()
# 
#     def trigger(self, duration=0):  # Update end time
#         now = ticks_ms()
#         if duration <= 0:  # Use default set by constructor
#             duration = self._duration
#         self._retrn = None
#         is_running = self()
#         tstop = self._tstop  # Current stop time
#         # Retriggering normally just updates ._tstop for ._timer
#         self._tstop = ticks_add(now, duration)
#         # Identify special case where we are bringing the end time forward
#         can = is_running and duration < ticks_diff(tstop, now)
#         if not is_running or can:
#             schedule(self._do_trig, can)
# 
#     def _trig(self, can):
#         if can:
#             self._ktask.cancel()
#         self._ktask = asyncio.create_task(self._timer(can))
# 
#     def __call__(self):  # Current running status
#         return self._tstop is not None
# 
#     running = __call__
# 
#     def rvalue(self):
#         return self._retrn
# 
#     async def _timer(self, restart):
#         if restart:  # Restore cached end time
#             self._tstop = self._tsave
#         try:
#             twait = ticks_diff(self._tstop, ticks_ms())
#             while twait > 0:  # Must loop here: might be retriggered
#                 await asyncio.sleep_ms(twait)
#                 twait = ticks_diff(self._tstop, ticks_ms())
#             if self._func is not None:  # Timed out: execute callback
#                 self._retrn = launch(self._func, self._args)
#         finally:
#             self._tsave = self._tstop  # Save in case we restart.
#             self._tstop = None  # timer is stopped


import uasyncio as asyncio
from tft.driver.ugui import Touchable, dolittle, print_centered
from tft.primitives.delay_ms import Delay_ms
from tft.driver.constants import *
            old.visible = False
            old.show()
            new.visible = True
            new.show()
            self.user_callback(new, *new.callback_args)
        return self.current

    def greyed_out(self, val=None):
        if val is not None and self._greyed_out != val:
            self._greyed_out = val
            for button in self.lstbuttons:
                button.greyed_out(val)
            self.current.show()
        return self._greyed_out

    def _callback(self, button, *args):
        old = button
        old_index = self.lstbuttons.index(button)
        new = self.lstbuttons[(old_index + 1) % len(self.lstbuttons)]
        self.current = new
        old.visible = False
        old.show()
        new.visible = True
        new.busy = True # Don't respond to continued press
        new.show()
        self.user_callback(new, *args) # user gets button with args they specified

# Group of buttons at different locations, where pressing one shows
# only current button highlighted and oes callback from current one
class RadioButtons:

# Path: tft/driver/ugui.py
# class Touchable(NoTouch):
#     def __init__(self, location, font, height, width, fgcolor, bgcolor, fontcolor, border, can_drag, value, initial_value):
#         super().__init__(location, font, height, width, fgcolor, bgcolor, fontcolor, border, value, initial_value)
#         self.can_drag = can_drag
#         self.busy = False
#         self.was_touched = False
# 
#     def _set_callbacks(self, cb, args, cb_end=None, cbe_args=None):
#         self.callback = cb
#         self.args = args
#         if cb_end is not None:
#             self.cb_end = cb_end
#             self.cbe_args = cbe_args
# 
#     def greyed_out(self, val=None):
#         if val is not None and self._greyed_out != val:
#             self._greyed_out = val
#             self.draw_border()
#             self.redraw = True
#             self.show_if_current()
#         return self._greyed_out
# 
#     def _trytouch(self, x, y): # If touched in bounding box, process it otherwise do nothing
#         x0 = self.location[0]
#         x1 = self.location[0] + self.width
#         y0 = self.location[1]
#         y1 = self.location[1] + self.height
#         if x0 <= x <= x1 and y0 <= y <= y1:
#             self.was_touched = True
#             if not self.busy or self.can_drag:
#                 self._touched(x, y) # Called repeatedly for draggable objects
#                 self.busy = True # otherwise once only
# 
#     def _untouched(self): # Default if not defined in subclass
#         self.cb_end(self, *self.cbe_args) # Callback not a bound method so pass self
# 
# def dolittle(*_):
#     pass
# 
# def print_centered(tft, x, y, s, color, font, clip=False, scroll=False):
#     old_style = tft.getTextStyle()
#     length, height = get_stringsize(s, font)
#     tft.setTextStyle(color, None, 2, font)
#     tft.setTextPos(max(x - length // 2, 0), max(y - height // 2, 0), clip, scroll)
#     tft.printString(s)
#     tft.setTextStyle(*old_style)
# 
# Path: tft/primitives/delay_ms.py
# class Delay_ms:
#     verbose = False  # verbose and can_alloc retained to avoid breaking code.
#     def __init__(self, func=None, args=(), can_alloc=True, duration=1000):
#         self._func = func
#         self._args = args
#         self._duration = duration  # Default duration
#         self._tstop = None  # Stop time (ms). None signifies not running.
#         self._tsave = None  # Temporary storage for stop time
#         self._ktask = None  # timer task
#         self._retrn = None  # Return value of launched callable
#         self._do_trig = self._trig  # Avoid allocation in .trigger
# 
#     def stop(self):
#         if self._ktask is not None:
#             self._ktask.cancel()
# 
#     def trigger(self, duration=0):  # Update end time
#         now = ticks_ms()
#         if duration <= 0:  # Use default set by constructor
#             duration = self._duration
#         self._retrn = None
#         is_running = self()
#         tstop = self._tstop  # Current stop time
#         # Retriggering normally just updates ._tstop for ._timer
#         self._tstop = ticks_add(now, duration)
#         # Identify special case where we are bringing the end time forward
#         can = is_running and duration < ticks_diff(tstop, now)
#         if not is_running or can:
#             schedule(self._do_trig, can)
# 
#     def _trig(self, can):
#         if can:
#             self._ktask.cancel()
#         self._ktask = asyncio.create_task(self._timer(can))
# 
#     def __call__(self):  # Current running status
#         return self._tstop is not None
# 
#     running = __call__
# 
#     def rvalue(self):
#         return self._retrn
# 
#     async def _timer(self, restart):
#         if restart:  # Restore cached end time
#             self._tstop = self._tsave
#         try:
#             twait = ticks_diff(self._tstop, ticks_ms())
#             while twait > 0:  # Must loop here: might be retriggered
#                 await asyncio.sleep_ms(twait)
#                 twait = ticks_diff(self._tstop, ticks_ms())
#             if self._func is not None:  # Timed out: execute callback
#                 self._retrn = launch(self._func, self._args)
#         finally:
#             self._tsave = self._tstop  # Save in case we restart.
#             self._tstop = None  # timer is stopped


# Path: tft/widgets/buttons.py
import uasyncio as asyncio
from tft.driver.ugui import Touchable, dolittle, print_centered
from tft.primitives.delay_ms import Delay_ms
from tft.driver.constants import *

            old.visible = False
            old.show()
            new.visible = True
            new.show()
            self.user_callback(new, *new.callback_args)
        return self.current

    def greyed_out(self, val=None):
        if val is not None and self._greyed_out != val:
            self._greyed_out = val
            for button in self.lstbuttons:
                button.greyed_out(val)
            self.current.show()
        return self._greyed_out

    def _callback(self, button, *args):
        old = button
        old_index = self.lstbuttons.index(button)
        new = self.lstbuttons[(old_index + 1) % len(self.lstbuttons)]
        self.current = new
        old.visible = False
        old.show()
        new.visible = True
        new.busy = True # Don't respond to continued press
        new.show()
        self.user_callback(new, *args) # user gets button with args they specified

# Group of buttons at different locations, where pressing one shows
# only current button highlighted and oes callback from current one
class RadioButtons:

    def __init__(self, highlight, callback=dolittle, selected=0):