diff --git a/adafruit_display_text/__init__.py b/adafruit_display_text/__init__.py index 34b6046..0ed774a 100644 --- a/adafruit_display_text/__init__.py +++ b/adafruit_display_text/__init__.py @@ -5,6 +5,7 @@ """ Display Text module helper functions """ +from displayio import Group, Palette def wrap_text_to_pixels(string, max_width, font=None, indent0="", indent1=""): @@ -141,3 +142,224 @@ def chunks(lst, n): if the_lines[0][0] == " ": the_lines[0] = the_lines[0][1:] return the_lines + + +class LabelBase(Group): + """Super class that all other types of labels will extend. This contains + all of the properties and functions that work the same way in all labels. + + subclasses should implement _set_text, _set_font, and _set_line_spacing to + have the correct behavior fo rthat type of label. + + :param Font font: A font class that has ``get_bounding_box`` and ``get_glyph``. + Must include a capital M for measuring character size. + :param str text: Text to display + :param int max_glyphs: Unnecessary parameter (provided only for direct compability + with label.py) + :param int color: Color of all text in RGB hex + :param int background_color: Color of the background, use `None` for transparent + :param double line_spacing: Line spacing of text to display + :param boolean background_tight: Set `True` only if you want background box to tightly + surround text. When set to 'True' Padding parameters will be ignored. + :param int padding_top: Additional pixels added to background bounding box at top + :param int padding_bottom: Additional pixels added to background bounding box at bottom + :param int padding_left: Additional pixels added to background bounding box at left + :param int padding_right: Additional pixels added to background bounding box at right + :param (float,float) anchor_point: Point that anchored_position moves relative to. + Tuple with decimal percentage of width and height. + (E.g. (0,0) is top left, (1.0, 0.5): is middle right.) + :param (int,int) anchored_position: Position relative to the anchor_point. Tuple + containing x,y pixel coordinates. + :param int scale: Integer value of the pixel scaling + :param bool save_text: Set True to save the text string as a constant in the + label structure. Set False to reduce memory use. + :param: bool base_alignment: when True allows to align text label to the baseline. + This is helpful when two or more labels need to be aligned to the same baseline""" + + # pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments + def __init__( + self, + font, + x=0, + y=0, + text="", + max_glyphs=None, + # with label.py + color=0xFFFFFF, + background_color=None, + line_spacing=1.25, + background_tight=False, + padding_top=0, + padding_bottom=0, + padding_left=0, + padding_right=0, + anchor_point=None, + anchored_position=None, + save_text=True, # can reduce memory use if save_text = False + scale=1, + base_alignment=False, + **kwargs, + ): + super().__init__(max_size=1, x=x, y=y, scale=1) + + self._font = font + self.palette = Palette(2) + self._color = color + self._background_color = background_color + + self._bounding_box = None + self._anchor_point = anchor_point + self._anchored_position = anchored_position + + # local group will hold background and text + # the self group scale should always remain at 1, the self.local_group will + # be used to set the scale of the label + self.local_group = None + + self._text = text + + def _get_ascent_descent(self): + """ Private function to calculate ascent and descent font values """ + if hasattr(self.font, "ascent"): + return self.font.ascent, self.font.descent + + # check a few glyphs for maximum ascender and descender height + glyphs = "M j'" # choose glyphs with highest ascender and lowest + try: + self._font.load_glyphs(glyphs) + except AttributeError: + # Builtin font doesn't have or need load_glyphs + pass + # descender, will depend upon font used + ascender_max = descender_max = 0 + for char in glyphs: + this_glyph = self._font.get_glyph(ord(char)) + if this_glyph: + ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy) + descender_max = max(descender_max, -this_glyph.dy) + return ascender_max, descender_max + + def _get_ascent(self): + return self._get_ascent_descent()[0] + + @property + def font(self): + """Font to use for text display.""" + return self._font + + def _set_font(self, new_font): + # subclasses should override this + pass + + @font.setter + def font(self, new_font): + self._set_font(new_font) + + @property + def color(self): + """Color of the text as an RGB hex number.""" + return self._color + + @color.setter + def color(self, new_color): + self._color = new_color + if new_color is not None: + self.palette[1] = new_color + self.palette.make_opaque(1) + else: + self.palette[1] = 0 + self.palette.make_transparent(1) + + @property + def background_color(self): + """Color of the background as an RGB hex number.""" + return self._background_color + + @background_color.setter + def background_color(self, new_color): + self._background_color = new_color + if new_color is not None: + self.palette[0] = new_color + self.palette.make_opaque(0) + else: + self.palette[0] = 0 + self.palette.make_transparent(0) + + @property + def anchor_point(self): + """Point that anchored_position moves relative to. + Tuple with decimal percentage of width and height. + (E.g. (0,0) is top left, (1.0, 0.5): is middle right.)""" + return self._anchor_point + + @anchor_point.setter + def anchor_point(self, new_anchor_point): + self._anchor_point = new_anchor_point + self.anchored_position = ( + self._anchored_position + ) # update the anchored_position using setter + + @property + def anchored_position(self): + """Position relative to the anchor_point. Tuple containing x,y + pixel coordinates.""" + return self._anchored_position + + @anchored_position.setter + def anchored_position(self, new_position): + self._anchored_position = new_position + # Set anchored_position + if (self._anchor_point is not None) and (self._anchored_position is not None): + self.x = int( + new_position[0] + - (self._bounding_box[0] * self.scale) + - round(self._anchor_point[0] * (self._bounding_box[2] * self.scale)) + ) + self.y = int( + new_position[1] + - (self._bounding_box[1] * self.scale) + - round(self._anchor_point[1] * self._bounding_box[3] * self.scale) + ) + + @property + def scale(self): + """Set the scaling of the label, in integer values""" + return self.local_group.scale + + @scale.setter + def scale(self, new_scale): + self.local_group.scale = new_scale + self.anchored_position = self._anchored_position # update the anchored_position + + def _set_text(self, new_text, scale): + # subclasses should override this + pass + + @property + def text(self): + """Text to be displayed.""" + return self._text + + @text.setter # Cannot set color or background color with text setter, use separate setter + def text(self, new_text): + self._set_text(new_text, self.scale) + + @property + def bounding_box(self): + """An (x, y, w, h) tuple that completely covers all glyphs. The + first two numbers are offset from the x, y origin of this group""" + return tuple(self._bounding_box) + + @property + def line_spacing(self): + """The amount of space between lines of text, in multiples of the font's + bounding-box height. (E.g. 1.0 is the bounding-box height)""" + return self._line_spacing + + def _set_line_spacing(self, new_line_spacing): + # subclass should override this. + pass + + @line_spacing.setter + def line_spacing(self, new_line_spacing): + self._set_line_spacing(new_line_spacing) diff --git a/adafruit_display_text/bitmap_label.py b/adafruit_display_text/bitmap_label.py index bb5c723..4f3cd07 100755 --- a/adafruit_display_text/bitmap_label.py +++ b/adafruit_display_text/bitmap_label.py @@ -28,8 +28,10 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git" +from adafruit_display_text import LabelBase -class Label(displayio.Group): + +class Label(LabelBase): """A label displaying a string of text that is stored in a bitmap. Note: This ``bitmap_label.py`` library utilizes a bitmap to display the text. This method is memory-conserving relative to ``label.py``. @@ -75,81 +77,43 @@ class Label(displayio.Group): # Note: max_glyphs parameter is unnecessary, this is used for direct # compatibility with label.py - def __init__( - self, - font, - x=0, - y=0, - text="", - max_glyphs=None, # This input parameter is ignored, only present for compatibility - # with label.py - color=0xFFFFFF, - background_color=None, - line_spacing=1.25, - background_tight=False, - padding_top=0, - padding_bottom=0, - padding_left=0, - padding_right=0, - anchor_point=None, - anchored_position=None, - save_text=True, # can reduce memory use if save_text = False - scale=1, - base_alignment=False, - **kwargs, - ): + def __init__(self, font, **kwargs): - # instance the Group - # self Group will contain a single local_group which contains a Group (self.local_group) - # which contains a TileGrid (self.tilegrid) which contains the text bitmap (self.bitmap) - super().__init__( - max_size=1, - x=x, - y=y, - scale=1, - **kwargs, - ) - # the self group scale should always remain at 1, the self.local_group will - # be used to set the scale - # **kwargs will pass any additional arguments provided to the Label + super().__init__(font, **kwargs) self.local_group = displayio.Group( - max_size=1, scale=scale + max_size=1, scale=kwargs.get("scale", 1) ) # local_group holds the tileGrid and sets the scaling self.append( self.local_group ) # the local_group will always stay in the self Group - self._font = font - self._text = text + self._text = kwargs.get("text", "") # Create the two-color palette - self.palette = displayio.Palette(2) - self.color = color - self.background_color = background_color - self._anchor_point = anchor_point - self._anchored_position = anchored_position + self.color = kwargs.get("color", 0xFFFFFF) + self.background_color = kwargs.get("background_color", None) - self.base_alignment = base_alignment + self.base_alignment = kwargs.get("base_alignment", False) # call the text updater with all the arguments. self._reset_text( font=font, - x=x, - y=y, - text=text, - line_spacing=line_spacing, - background_tight=background_tight, - padding_top=padding_top, - padding_bottom=padding_bottom, - padding_left=padding_left, - padding_right=padding_right, - anchor_point=anchor_point, - anchored_position=anchored_position, - save_text=save_text, - scale=scale, - base_alignment=base_alignment, + x=kwargs.get("x", 0), + y=kwargs.get("y", 0), + text=kwargs.get("text", ""), + line_spacing=kwargs.get("line_spacing", 1.25), + background_tight=kwargs.get("background_tight", False), + padding_top=kwargs.get("padding_top", 0), + padding_bottom=kwargs.get("padding_bottom", 0), + padding_left=kwargs.get("padding_left", 0), + padding_right=kwargs.get("padding_right", 0), + anchor_point=kwargs.get("anchor_point", None), + anchored_position=kwargs.get("anchored_position", None), + save_text=kwargs.get("save_text", True), + scale=kwargs.get("scale", 1), + base_alignment=kwargs.get("base_alignment", False), ) def _reset_text( @@ -313,30 +277,6 @@ def _reset_text( ) # set the anchored_position with setter after bitmap is created, sets the # x,y positions of the label - def _get_ascent_descent(self): - """ Private function to calculate ascent and descent font values """ - if hasattr(self.font, "ascent"): - return self.font.ascent, self.font.descent - - # check a few glyphs for maximum ascender and descender height - glyphs = "M j'" # choose glyphs with highest ascender and lowest - try: - self._font.load_glyphs(glyphs) - except AttributeError: - # Builtin font doesn't have or need load_glyphs - pass - # descender, will depend upon font used - ascender_max = descender_max = 0 - for char in glyphs: - this_glyph = self._font.get_glyph(ord(char)) - if this_glyph: - ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy) - descender_max = max(descender_max, -this_glyph.dy) - return ascender_max, descender_max - - def _get_ascent(self): - return self._get_ascent_descent()[0] - @staticmethod def _line_spacing_ypixels(font, line_spacing): # Note: Scaling is provided at the Group level @@ -566,119 +506,18 @@ def _blit( elif y_placement > bitmap.height: break - @property - def bounding_box(self): - """An (x, y, w, h) tuple that completely covers all glyphs. The - first two numbers are offset from the x, y origin of this group""" - return self._bounding_box - - @property - def scale(self): - """Set the scaling of the label, in integer values""" - return self.local_group.scale - - @scale.setter - def scale(self, new_scale): - self.local_group.scale = new_scale - self.anchored_position = self._anchored_position # update the anchored_position - - @property - def line_spacing(self): - """The amount of space between lines of text, in multiples of the font's - bounding-box height. (E.g. 1.0 is the bounding-box height)""" - return self._line_spacing - - @line_spacing.setter - def line_spacing(self, new_line_spacing): + def _set_line_spacing(self, new_line_spacing): if self._save_text: self._reset_text(line_spacing=new_line_spacing, scale=self.scale) else: raise RuntimeError("line_spacing is immutable when save_text is False") - @property - def color(self): - """Color of the text as an RGB hex number.""" - return self._color - - @color.setter - def color(self, new_color): - self._color = new_color - if new_color is not None: - self.palette[1] = new_color - self.palette.make_opaque(1) - else: - self.palette[1] = 0 - self.palette.make_transparent(1) - - @property - def background_color(self): - """Color of the background as an RGB hex number.""" - return self._background_color - - @background_color.setter - def background_color(self, new_color): - self._background_color = new_color - if new_color is not None: - self.palette[0] = new_color - self.palette.make_opaque(0) - else: - self.palette[0] = 0 - self.palette.make_transparent(0) - - @property - def text(self): - """Text to be displayed.""" - return self._text - - @text.setter # Cannot set color or background color with text setter, use separate setter - def text(self, new_text): - self._reset_text(text=new_text, scale=self.scale) - - @property - def font(self): - """Font to use for text display.""" - return self._font - - @font.setter - def font(self, new_font): + def _set_font(self, new_font): self._font = new_font if self._save_text: self._reset_text(font=new_font, scale=self.scale) else: raise RuntimeError("font is immutable when save_text is False") - @property - def anchor_point(self): - """Point that anchored_position moves relative to. - Tuple with decimal percentage of width and height. - (E.g. (0,0) is top left, (1.0, 0.5): is middle right.)""" - return self._anchor_point - - @anchor_point.setter - def anchor_point(self, new_anchor_point): - self._anchor_point = new_anchor_point - self.anchored_position = ( - self._anchored_position - ) # update the anchored_position using setter - - @property - def anchored_position(self): - """Position relative to the anchor_point. Tuple containing x,y - pixel coordinates.""" - return self._anchored_position - - @anchored_position.setter - def anchored_position(self, new_position): - self._anchored_position = new_position - # Set anchored_position - if (self._anchor_point is not None) and (self._anchored_position is not None): - self.x = int( - new_position[0] - - (self._bounding_box[0] * self.scale) - - round(self._anchor_point[0] * (self._bounding_box[2] * self.scale)) - ) - self.y = int( - new_position[1] - - (self._bounding_box[1] * self.scale) - - round(self._anchor_point[1] * self._bounding_box[3] * self.scale) - ) + def _set_text(self, new_text, scale): + self._reset_text(text=new_text, scale=self.scale) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 5549871..ed6b2e9 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -27,8 +27,10 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git" +from adafruit_display_text import LabelBase -class Label(displayio.Group): + +class Label(LabelBase): """A label displaying a string of text. The origin point set by ``x`` and ``y`` properties will be the left edge of the bounding box, and in the center of a M glyph (if its one line), or the (number of lines * linespacing + M)/2. That is, @@ -66,96 +68,79 @@ class Label(displayio.Group): # pylint: disable=too-many-instance-attributes, too-many-locals # This has a lot of getters/setters, maybe it needs cleanup. - def __init__( - self, - font, - *, - x=0, - y=0, - text="", - max_glyphs=None, - color=0xFFFFFF, - background_color=None, - line_spacing=1.25, - background_tight=False, - padding_top=0, - padding_bottom=0, - padding_left=0, - padding_right=0, - anchor_point=None, - anchored_position=None, - scale=1, - base_alignment=False, - **kwargs - ): + def __init__(self, font, **kwargs): + super().__init__(font, **kwargs) + + max_glyphs = kwargs.get("max_glyphs", None) + text = kwargs.get("text", None) + if not max_glyphs and not text: raise RuntimeError("Please provide a max size, or initial text") if not max_glyphs: max_glyphs = len(text) # add one to max_size for the background bitmap tileGrid - # instance the Group - # self Group will contain a single local_group which contains a Group (self.local_group) - # which contains a TileGrid - # The self scale should always be 1 - super().__init__(max_size=1, scale=1, **kwargs) # local_group will set the scale - self.local_group = displayio.Group(max_size=max_glyphs + 1, scale=scale) + self.local_group = displayio.Group( + max_size=max_glyphs + 1, scale=kwargs.get("scale", 1) + ) self.append(self.local_group) self.width = max_glyphs self._font = font self._text = None - self._anchor_point = anchor_point - self.x = x - self.y = y + self._anchor_point = kwargs.get("anchor_point", None) + self.x = kwargs.get("x", 0) + self.y = kwargs.get("y", 0) self.height = self._font.get_bounding_box()[1] - self._line_spacing = line_spacing - self._boundingbox = None + self._line_spacing = kwargs.get("line_spacing", 1.25) + self._bounding_box = None - self._background_tight = ( - background_tight # sets padding status for text background box - ) + self._background_tight = kwargs.get( + "background_tight", False + ) # sets padding status for text background box # Create the two-color text palette self.palette = displayio.Palette(2) self.palette[0] = 0 self.palette.make_transparent(0) - self.color = color + self.color = kwargs.get("color", 0xFFFFFF) - self._background_color = background_color + self._background_color = kwargs.get("background_color", None) self._background_palette = displayio.Palette(1) self._added_background_tilegrid = False - self._padding_top = padding_top - self._padding_bottom = padding_bottom - self._padding_left = padding_left - self._padding_right = padding_right - self.base_alignment = base_alignment + self._padding_top = kwargs.get("padding_top", 0) + self._padding_bottom = kwargs.get("padding_bottom", 0) + self._padding_left = kwargs.get("padding_left", 0) + self._padding_right = kwargs.get("padding_right", 0) + self.base_alignment = kwargs.get("base_alignment", False) if text is not None: self._update_text(str(text)) - if (anchored_position is not None) and (anchor_point is not None): - self.anchored_position = anchored_position + if (kwargs.get("anchored_position", None) is not None) and ( + kwargs.get("anchor_point", None) is not None + ): + self.anchored_position = kwargs.get("anchored_position", None) def _create_background_box(self, lines, y_offset): """Private Class function to create a background_box :param lines: int number of lines :param y_offset: int y pixel bottom coordinate for the background_box""" - left = self._boundingbox[0] + left = self._bounding_box[0] if self._background_tight: # draw a tight bounding box - box_width = self._boundingbox[2] - box_height = self._boundingbox[3] + box_width = self._bounding_box[2] + box_height = self._bounding_box[3] x_box_offset = 0 - y_box_offset = self._boundingbox[1] + y_box_offset = self._bounding_box[1] else: # draw a "loose" bounding box to include any ascenders/descenders. ascent, descent = self._get_ascent_descent() - box_width = self._boundingbox[2] + self._padding_left + self._padding_right + box_width = self._bounding_box[2] + self._padding_left + self._padding_right x_box_offset = -self._padding_left box_height = ( (ascent + descent) @@ -181,30 +166,6 @@ def _create_background_box(self, lines, y_offset): return tile_grid - def _get_ascent_descent(self): - """ Private function to calculate ascent and descent font values """ - if hasattr(self.font, "ascent"): - return self.font.ascent, self.font.descent - - # check a few glyphs for maximum ascender and descender height - glyphs = "M j'" # choose glyphs with highest ascender and lowest - try: - self._font.load_glyphs(glyphs) - except AttributeError: - # Builtin font doesn't have or need load_glyphs - pass - # descender, will depend upon font used - ascender_max = descender_max = 0 - for char in glyphs: - this_glyph = self._font.get_glyph(ord(char)) - if this_glyph: - ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy) - descender_max = max(descender_max, -this_glyph.dy) - return ascender_max, descender_max - - def _get_ascent(self): - return self._get_ascent_descent()[0] - def _update_background_color(self, new_color): """Private class function that allows updating the font box background color :param new_color: int color as an RGB hex number.""" @@ -227,10 +188,10 @@ def _update_background_color(self, new_color): if ( (len(self._text) > 0) and ( - self._boundingbox[2] + self._padding_left + self._padding_right > 0 + self._bounding_box[2] + self._padding_left + self._padding_right > 0 ) and ( - self._boundingbox[3] + self._padding_top + self._padding_bottom > 0 + self._bounding_box[3] + self._padding_top + self._padding_bottom > 0 ) ): # This can be simplified in CP v6.0, when group.append(0) bug is corrected @@ -249,10 +210,10 @@ def _update_background_color(self, new_color): if ( (len(self._text) > 0) and ( - self._boundingbox[2] + self._padding_left + self._padding_right > 0 + self._bounding_box[2] + self._padding_left + self._padding_right > 0 ) and ( - self._boundingbox[3] + self._padding_top + self._padding_bottom > 0 + self._bounding_box[3] + self._padding_top + self._padding_bottom > 0 ) ): self.local_group[0] = self._create_background_box(lines, y_offset) @@ -333,59 +294,12 @@ def _update_text( while len(self.local_group) > tilegrid_count: # i: self.local_group.pop() self._text = new_text - self._boundingbox = (left, top, right - left, bottom - top) + self._bounding_box = (left, top, right - left, bottom - top) if self.background_color is not None: self._update_background_color(self._background_color) - @property - def bounding_box(self): - """An (x, y, w, h) tuple that completely covers all glyphs. The - first two numbers are offset from the x, y origin of this group""" - return tuple(self._boundingbox) - - @property - def line_spacing(self): - """The amount of space between lines of text, in multiples of the font's - bounding-box height. (E.g. 1.0 is the bounding-box height)""" - return self._line_spacing - - @line_spacing.setter - def line_spacing(self, spacing): - self._line_spacing = spacing - self.text = self._text # redraw the box - - @property - def color(self): - """Color of the text as an RGB hex number.""" - return self.palette[1] - - @color.setter - def color(self, new_color): - self._color = new_color - if new_color is not None: - self.palette[1] = new_color - self.palette.make_opaque(1) - else: - self.palette[1] = 0 - self.palette.make_transparent(1) - - @property - def background_color(self): - """Color of the background as an RGB hex number.""" - return self._background_color - - @background_color.setter - def background_color(self, new_color): - self._update_background_color(new_color) - - @property - def text(self): - """Text to display.""" - return self._text - - @text.setter - def text(self, new_text): + def _reset_text(self, new_text): try: current_anchored_position = self.anchored_position self._update_text(str(new_text)) @@ -393,24 +307,7 @@ def text(self, new_text): except RuntimeError as run_error: raise RuntimeError("Text length exceeds max_glyphs") from run_error - @property - def scale(self): - """Set the scaling of the label, in integer values""" - return self.local_group.scale - - @scale.setter - def scale(self, new_scale): - current_anchored_position = self.anchored_position - self.local_group.scale = new_scale - self.anchored_position = current_anchored_position - - @property - def font(self): - """Font to use for text display.""" - return self._font - - @font.setter - def font(self, new_font): + def _set_font(self, new_font): old_text = self._text current_anchored_position = self.anchored_position self._text = "" @@ -419,52 +316,9 @@ def font(self, new_font): self._update_text(str(old_text)) self.anchored_position = current_anchored_position - @property - def anchor_point(self): - """Point that anchored_position moves relative to. - Tuple with decimal percentage of width and height. - (E.g. (0,0) is top left, (1.0, 0.5): is middle right.)""" - return self._anchor_point - - @anchor_point.setter - def anchor_point(self, new_anchor_point): - if self._anchor_point is not None: - current_anchored_position = self.anchored_position - self._anchor_point = new_anchor_point - self.anchored_position = current_anchored_position - else: - self._anchor_point = new_anchor_point - - @property - def anchored_position(self): - """Position relative to the anchor_point. Tuple containing x,y - pixel coordinates.""" - if self._anchor_point is None: - return None - return ( - int( - self.x - + (self._boundingbox[0] * self.scale) - + round(self._anchor_point[0] * self._boundingbox[2] * self.scale) - ), - int( - self.y - + (self._boundingbox[1] * self.scale) - + round(self._anchor_point[1] * self._boundingbox[3] * self.scale) - ), - ) + def _set_line_spacing(self, new_line_spacing): + self._line_spacing = new_line_spacing + self.text = self._text # redraw the box - @anchored_position.setter - def anchored_position(self, new_position): - if (self._anchor_point is None) or (new_position is None): - return # Note: anchor_point must be set before setting anchored_position - self.x = int( - new_position[0] - - (self._boundingbox[0] * self.scale) - - round(self._anchor_point[0] * (self._boundingbox[2] * self.scale)) - ) - self.y = int( - new_position[1] - - (self._boundingbox[1] * self.scale) - - round(self._anchor_point[1] * self._boundingbox[3] * self.scale) - ) + def _set_text(self, new_text, scale): + self._reset_text(new_text)