# Path: gui/core/lcd160_gui.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:
#             tft = self.tft
#             tft.usegrey(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  # Cleared by Screen._touchtest
#             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
# 
# class IFont:
#     size = ((4, 5), (6, 7), (8, 8), (9, 13))  # (w, h) for each font
#     def __init__(self, family, scale=0, bold_h=0, bold_v=0):
#         self.bold = (bold_h & 3) | ((bold_v & 3) << 2)
#         self.scale = scale
#         self.width = (scale + 1) * self.size[family][0]
#         self.vheight = (scale + 1) * self.size[family][1]
#         self.family = family
# 
#     def stringsize(self, s):
#         return len(s) * self.width, self.vheight
# 
#     def render(self, tft, x, y, s, style):
#         tft.set_pos(x, y)
#         tft.set_text_color(tft.rgb(*style[0]), tft.rgb(*style[1]))
#         tft.set_font(self.family, self.scale, self.bold, 0, 0)
#         tft.write(s)
# 
#     def height(self):
#         return self.vheight
# 
#     def max_width(self):
#         return self.width
# 
#     def hmap(self):
#         return True
# 
#     def reverse(self):
#         return False
# 
#     def monospaced(self):
#         return True
# 
# def print_left(tft, x, y, s, style, tab=32):
#     if s == '':
#         return
#     tft.text_style(style)
#     tft.set_text_pos(x, y)
#     font = style[2]
#     if isinstance(font, IFont):  # Tabs unsupported for internal fonts
#         return font.render(tft, x, y, s, style)
#     tft.print_string(s, tab=tab)


from gui.core.lcd160_gui import Touchable, IFont, print_left
        super().__init__(location, font, height, width, fgcolor, bgcolor,
                         fontcolor, border, repeat, 0, 0)
        self.nlines = nlines
        self.clip = clip
        self.tab = tab
        self.lines = []
        self.start = 0  # Start line for display

    def _add_lines(self, s):
        width = self.width - 2 * self.border
        font = self.text_style[2]
        n = -1  # Index into string
        newline = True
        while True:
            n += 1
            if newline:
                newline = False
                ls = n  # Start of line being processed
                col = 0  # Column relative to text area
            if n >= len(s):  # End of string
                if n > ls:
                    self.lines.append(s[ls :])
                return
            c = s[n]  # Current char
            if c == '\n':
                self.lines.append(s[ls : n])
                newline = True
                continue  # Line fits window
            if c == '\t':
                col += self.tab - col % self.tab

# Path: gui/core/lcd160_gui.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:
#             tft = self.tft
#             tft.usegrey(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  # Cleared by Screen._touchtest
#             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
# 
# class IFont:
#     size = ((4, 5), (6, 7), (8, 8), (9, 13))  # (w, h) for each font
#     def __init__(self, family, scale=0, bold_h=0, bold_v=0):
#         self.bold = (bold_h & 3) | ((bold_v & 3) << 2)
#         self.scale = scale
#         self.width = (scale + 1) * self.size[family][0]
#         self.vheight = (scale + 1) * self.size[family][1]
#         self.family = family
# 
#     def stringsize(self, s):
#         return len(s) * self.width, self.vheight
# 
#     def render(self, tft, x, y, s, style):
#         tft.set_pos(x, y)
#         tft.set_text_color(tft.rgb(*style[0]), tft.rgb(*style[1]))
#         tft.set_font(self.family, self.scale, self.bold, 0, 0)
#         tft.write(s)
# 
#     def height(self):
#         return self.vheight
# 
#     def max_width(self):
#         return self.width
# 
#     def hmap(self):
#         return True
# 
#     def reverse(self):
#         return False
# 
#     def monospaced(self):
#         return True
# 
# def print_left(tft, x, y, s, style, tab=32):
#     if s == '':
#         return
#     tft.text_style(style)
#     tft.set_text_pos(x, y)
#     font = style[2]
#     if isinstance(font, IFont):  # Tabs unsupported for internal fonts
#         return font.render(tft, x, y, s, style)
#     tft.print_string(s, tab=tab)


# Path: gui/widgets/textbox.py
from gui.core.lcd160_gui import Touchable, IFont, print_left

        super().__init__(location, font, height, width, fgcolor, bgcolor,
                         fontcolor, border, repeat, 0, 0)
        self.nlines = nlines
        self.clip = clip
        self.tab = tab
        self.lines = []
        self.start = 0  # Start line for display

    def _add_lines(self, s):
        width = self.width - 2 * self.border
        font = self.text_style[2]
        n = -1  # Index into string
        newline = True
        while True:
            n += 1
            if newline:
                newline = False
                ls = n  # Start of line being processed
                col = 0  # Column relative to text area
            if n >= len(s):  # End of string
                if n > ls:
                    self.lines.append(s[ls :])
                return
            c = s[n]  # Current char
            if c == '\n':
                self.lines.append(s[ls : n])
                newline = True
                continue  # Line fits window
            if c == '\t':
                col += self.tab - col % self.tab

            elif isinstance(font, IFont):  # Monospaced