From 8478f715485f2dcb5599279182c8ab25252a87bf Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Tue, 9 Mar 2021 23:44:36 -0500 Subject: [PATCH 1/8] Initial Changes --- adafruit_display_text/__init__.py | 6 +- adafruit_display_text/label.py | 196 +++++++++++++++++++++++++----- 2 files changed, 169 insertions(+), 33 deletions(-) diff --git a/adafruit_display_text/__init__.py b/adafruit_display_text/__init__.py index 4ed611d..56133ce 100644 --- a/adafruit_display_text/__init__.py +++ b/adafruit_display_text/__init__.py @@ -184,7 +184,10 @@ class LabelBase(Group): This is helpful when two or more labels need to be aligned to the same baseline :param: (int,str) tab_replacement: tuple with tab character replace information. When (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by - tab character""" + tab character + :param: str label_direction: string defining the label text orientation. There are 5 + configurations possibles ``LTR``:Left-To-Right ``RTL``:Right-To-Left + ``TTB``:TTB Top-To-Bottom ``UPR``:Upwards ``DWR``:Downwards. It defaults to ``LTR`` """ # pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments def __init__( @@ -208,6 +211,7 @@ def __init__( scale: int = 1, base_alignment: bool = False, tab_replacement: Tuple[int, str] = (4, " "), + label_direction: str = "LTR", **kwargs, ) -> None: super().__init__(max_size=1, x=x, y=y, scale=1) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index b231d74..13cf844 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -66,7 +66,10 @@ class Label(LabelBase): This is helpful when two or more labels need to be aligned to the same baseline :param: (int,str) tab_replacement: tuple with tab character replace information. When (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by - tab character""" + tab character + :param: str label_direction: string defining the label text orientation. There are 5 + configurations possibles ``LTR``:Left-To-Right ``RTL``:Right-To-Left + ``TTB``:TTB Top-To-Bottom ``UPR``:Upwards ``DWR``:Downwards. It defaults to ``STR``""" # pylint: disable=too-many-instance-attributes, too-many-locals # This has a lot of getters/setters, maybe it needs cleanup. @@ -122,6 +125,7 @@ def __init__(self, font, **kwargs) -> None: self._padding_left = kwargs.get("padding_left", 0) self._padding_right = kwargs.get("padding_right", 0) self.base_alignment = kwargs.get("base_alignment", False) + self.label_type = kwargs.get("label_direction", "LTR") if text is not None: self._update_text(str(text)) @@ -136,7 +140,6 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: :param y_offset: int y pixel bottom coordinate for the background_box""" left = self._bounding_box[0] - if self._background_tight: # draw a tight bounding box box_width = self._bounding_box[2] box_height = self._bounding_box[3] @@ -146,14 +149,33 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: else: # draw a "loose" bounding box to include any ascenders/descenders. ascent, descent = self._get_ascent_descent() - box_width = self._bounding_box[2] + self._padding_left + self._padding_right - x_box_offset = -self._padding_left - box_height = ( - (ascent + descent) - + int((lines - 1) * self.height * self._line_spacing) - + self._padding_top - + self._padding_bottom - ) + if ( + self.label_type == "UPR" + or self.label_type == "DWR" + or self.label_type == "TTB" + ): + box_height = ( + self._bounding_box[3] + self._padding_top + self._padding_bottom + ) + x_box_offset = -self._padding_bottom + box_width = ( + (ascent + descent) + + int((lines - 1) * self.width * self._line_spacing) + + self._padding_left + + self._padding_right + ) + else: + box_width = ( + self._bounding_box[2] + self._padding_left + self._padding_right + ) + x_box_offset = -self._padding_left + box_height = ( + (ascent + descent) + + int((lines - 1) * self.height * self._line_spacing) + + self._padding_top + + self._padding_bottom + ) + if self.base_alignment: y_box_offset = -ascent - self._padding_top else: @@ -162,12 +184,25 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: box_width = max(0, box_width) # remove any negative values box_height = max(0, box_height) # remove any negative values + if self.label_type == "UPR": + movx = left + x_box_offset + movy = -box_height - x_box_offset + elif self.label_type == "DWR": + movx = left + x_box_offset + movy = x_box_offset + elif self.label_type == "TTB": + movx = left + x_box_offset + movy = x_box_offset + else: + movx = left + x_box_offset + movy = y_box_offset + background_bitmap = displayio.Bitmap(box_width, box_height, 1) tile_grid = displayio.TileGrid( background_bitmap, pixel_shader=self._background_palette, - x=left + x_box_offset, - y=y_box_offset, + x=movx, + y=movy, ) return tile_grid @@ -239,12 +274,19 @@ def _update_text( i = 0 tilegrid_count = i if self.base_alignment: - self._y_offset = 0 + y_offset = 0 else: - self._y_offset = self._get_ascent() // 2 - - right = top = bottom = 0 - left = None + y_offset = self._get_ascent() // 2 + + if self.label_type == "RTL": + left = top = bottom = 0 + right = None + elif self.label_type == "LTR": + right = top = bottom = 0 + left = None + else: + top = right = left = 0 + bottom = 0 for character in new_text: if character == "\n": @@ -254,17 +296,74 @@ def _update_text( glyph = self._font.get_glyph(ord(character)) if not glyph: continue - right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) - if x == 0: - if left is None: - left = glyph.dx + + if self.label_type == "LTR" or self.label_type == "RTL": + bottom = max(bottom, y - glyph.dy + y_offset) + if y == 0: # first line, find the Ascender height + top = min(top, -glyph.height - glyph.dy + y_offset) + position_y = y - glyph.height - glyph.dy + y_offset + + if self.label_type == "LTR": + right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) + if x == 0: + if left is None: + left = glyph.dx + else: + left = min(left, glyph.dx) + position_x = x + glyph.dx else: - left = min(left, glyph.dx) - if y == 0: # first line, find the Ascender height - top = min(top, -glyph.height - glyph.dy + self._y_offset) - bottom = max(bottom, y - glyph.dy + self._y_offset) - position_y = y - glyph.height - glyph.dy + self._y_offset - position_x = x + glyph.dx + left = max( + left, abs(x) + glyph.shift_x, abs(x) + glyph.width + glyph.dx + ) + if x == 0: + if right is None: + right = glyph.dx + else: + right = max(right, glyph.dx) + position_x = x - glyph.width + + if self.label_type == "TTB": + if x == 0: + if left is None: + left = glyph.dx + else: + left = min(left, glyph.dx) + if y == 0: + top = min(top, -glyph.dy) + + bottom = max(bottom, y + glyph.height, y + glyph.height + glyph.dy) + right = max( + right, x + glyph.width + glyph.dx, x + glyph.shift_x + glyph.dx + ) + position_y = y + glyph.dy + position_x = x - glyph.width // 2 + y_offset + + if self.label_type == "UPR": + if x == 0: + if bottom is None: + bottom = -glyph.dx + + if y == 0: # first line, find the Ascender height + bottom = min(bottom, -glyph.dy) + left = min(left, x - glyph.height + y_offset) + top = min(top, y - glyph.width - glyph.dx, y - glyph.shift_x) + right = max(right, x + glyph.height, x + glyph.height - glyph.dy) + position_y = y - glyph.width - glyph.dx + position_x = x - glyph.height - glyph.dy + y_offset + + if self.label_type == "DWR": + if y == 0: + if top is None: + top = -glyph.dx + top = min(top, -glyph.dx) + if x == 0: + left = min(left, -glyph.dy) + left = min(left, x, x - glyph.dy - y_offset) + bottom = max(bottom, y + glyph.width + glyph.dx, y + glyph.shift_x) + right = max(right, x + glyph.height) + position_y = y + glyph.dx + position_x = x + glyph.dy - y_offset + if glyph.width > 0 and glyph.height > 0: try: # pylint: disable=unexpected-keyword-arg @@ -286,23 +385,56 @@ def _update_text( x=position_x, y=position_y, ) + + if self.label_type == "UPR": + face.transpose_xy = True + face.flip_x = True + if self.label_type == "DWR": + face.transpose_xy = True + face.flip_y = True + if tilegrid_count < len(self.local_group): self.local_group[tilegrid_count] = face else: self.local_group.append(face) tilegrid_count += 1 - x += glyph.shift_x + if self.label_type == "RTL": + x = x - glyph.shift_x + if self.label_type == "TTB": + if glyph.height < 2: + y = y + glyph.shift_x + else: + y = y + glyph.height + 1 + if self.label_type == "UPR": + y = y - glyph.shift_x + if self.label_type == "DWR": + y = y + glyph.shift_x + if self.label_type == "LTR": + x = x + glyph.shift_x i += 1 - # Remove the rest - if left is None: + if self.label_type == "LTR" and left is None: left = 0 + if self.label_type == "RTL" and right is None: + right = 0 + if self.label_type == "TTB" and top is None: + top = 0 while len(self.local_group) > tilegrid_count: # i: self.local_group.pop() - self._text = new_text - self._bounding_box = (left, top, right - left, bottom - top) + # pylint: disable=invalid-unary-operand-type + if self.label_type == "RTL": + self._bounding_box = (-left, top, left - right, bottom - top) + if self.label_type == "TTB": + self._bounding_box = (left, top, right - left, bottom - top) + if self.label_type == "UPR": + self._bounding_box = (left, top, right, bottom - top) + if self.label_type == "DWR": + self._bounding_box = (left, top, right, bottom - top) + if self.label_type == "LTR": + self._bounding_box = (left, top, right - left, bottom - top) + self._text = new_text if self.background_color is not None: self._update_background_color(self._background_color) From 6a1880622668c902ae7d25313b472ffc15428316 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 10 Mar 2021 01:58:23 -0500 Subject: [PATCH 2/8] Pylint and Black --- adafruit_display_text/label.py | 211 ++++++--------------------------- 1 file changed, 39 insertions(+), 172 deletions(-) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 13cf844..5751fc3 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -66,10 +66,7 @@ class Label(LabelBase): This is helpful when two or more labels need to be aligned to the same baseline :param: (int,str) tab_replacement: tuple with tab character replace information. When (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by - tab character - :param: str label_direction: string defining the label text orientation. There are 5 - configurations possibles ``LTR``:Left-To-Right ``RTL``:Right-To-Left - ``TTB``:TTB Top-To-Bottom ``UPR``:Upwards ``DWR``:Downwards. It defaults to ``STR``""" + tab character""" # pylint: disable=too-many-instance-attributes, too-many-locals # This has a lot of getters/setters, maybe it needs cleanup. @@ -125,7 +122,6 @@ def __init__(self, font, **kwargs) -> None: self._padding_left = kwargs.get("padding_left", 0) self._padding_right = kwargs.get("padding_right", 0) self.base_alignment = kwargs.get("base_alignment", False) - self.label_type = kwargs.get("label_direction", "LTR") if text is not None: self._update_text(str(text)) @@ -140,6 +136,7 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: :param y_offset: int y pixel bottom coordinate for the background_box""" left = self._bounding_box[0] + if self._background_tight: # draw a tight bounding box box_width = self._bounding_box[2] box_height = self._bounding_box[3] @@ -149,33 +146,14 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: else: # draw a "loose" bounding box to include any ascenders/descenders. ascent, descent = self._get_ascent_descent() - if ( - self.label_type == "UPR" - or self.label_type == "DWR" - or self.label_type == "TTB" - ): - box_height = ( - self._bounding_box[3] + self._padding_top + self._padding_bottom - ) - x_box_offset = -self._padding_bottom - box_width = ( - (ascent + descent) - + int((lines - 1) * self.width * self._line_spacing) - + self._padding_left - + self._padding_right - ) - else: - box_width = ( - self._bounding_box[2] + self._padding_left + self._padding_right - ) - x_box_offset = -self._padding_left - box_height = ( - (ascent + descent) - + int((lines - 1) * self.height * self._line_spacing) - + self._padding_top - + self._padding_bottom - ) - + box_width = self._bounding_box[2] + self._padding_left + self._padding_right + x_box_offset = -self._padding_left + box_height = ( + (ascent + descent) + + int((lines - 1) * self.height * self._line_spacing) + + self._padding_top + + self._padding_bottom + ) if self.base_alignment: y_box_offset = -ascent - self._padding_top else: @@ -184,30 +162,17 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: box_width = max(0, box_width) # remove any negative values box_height = max(0, box_height) # remove any negative values - if self.label_type == "UPR": - movx = left + x_box_offset - movy = -box_height - x_box_offset - elif self.label_type == "DWR": - movx = left + x_box_offset - movy = x_box_offset - elif self.label_type == "TTB": - movx = left + x_box_offset - movy = x_box_offset - else: - movx = left + x_box_offset - movy = y_box_offset - background_bitmap = displayio.Bitmap(box_width, box_height, 1) tile_grid = displayio.TileGrid( background_bitmap, pixel_shader=self._background_palette, - x=movx, - y=movy, + x=left + x_box_offset, + y=y_box_offset, ) return tile_grid - def _update_background_color(self, new_color: int) -> None: + 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.""" @@ -262,10 +227,9 @@ def _update_background_color(self, new_color: int) -> None: self.local_group.pop(0) self._added_background_tilegrid = False - # pylint: disable = too-many-branches, too-many-statements def _update_text( - self, new_text: str - ) -> None: # pylint: disable=too-many-locals ,too-many-branches, too-many-statements + self, new_text + ): # pylint: disable=too-many-locals ,too-many-branches, too-many-statements x = 0 y = 0 if self._added_background_tilegrid: @@ -274,19 +238,12 @@ def _update_text( i = 0 tilegrid_count = i if self.base_alignment: - y_offset = 0 + self._y_offset = 0 else: - y_offset = self._get_ascent() // 2 - - if self.label_type == "RTL": - left = top = bottom = 0 - right = None - elif self.label_type == "LTR": - right = top = bottom = 0 - left = None - else: - top = right = left = 0 - bottom = 0 + self._y_offset = self._get_ascent() // 2 + + right = top = bottom = 0 + left = None for character in new_text: if character == "\n": @@ -296,74 +253,17 @@ def _update_text( glyph = self._font.get_glyph(ord(character)) if not glyph: continue - - if self.label_type == "LTR" or self.label_type == "RTL": - bottom = max(bottom, y - glyph.dy + y_offset) - if y == 0: # first line, find the Ascender height - top = min(top, -glyph.height - glyph.dy + y_offset) - position_y = y - glyph.height - glyph.dy + y_offset - - if self.label_type == "LTR": - right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) - if x == 0: - if left is None: - left = glyph.dx - else: - left = min(left, glyph.dx) - position_x = x + glyph.dx + right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) + if x == 0: + if left is None: + left = glyph.dx else: - left = max( - left, abs(x) + glyph.shift_x, abs(x) + glyph.width + glyph.dx - ) - if x == 0: - if right is None: - right = glyph.dx - else: - right = max(right, glyph.dx) - position_x = x - glyph.width - - if self.label_type == "TTB": - if x == 0: - if left is None: - left = glyph.dx - else: - left = min(left, glyph.dx) - if y == 0: - top = min(top, -glyph.dy) - - bottom = max(bottom, y + glyph.height, y + glyph.height + glyph.dy) - right = max( - right, x + glyph.width + glyph.dx, x + glyph.shift_x + glyph.dx - ) - position_y = y + glyph.dy - position_x = x - glyph.width // 2 + y_offset - - if self.label_type == "UPR": - if x == 0: - if bottom is None: - bottom = -glyph.dx - - if y == 0: # first line, find the Ascender height - bottom = min(bottom, -glyph.dy) - left = min(left, x - glyph.height + y_offset) - top = min(top, y - glyph.width - glyph.dx, y - glyph.shift_x) - right = max(right, x + glyph.height, x + glyph.height - glyph.dy) - position_y = y - glyph.width - glyph.dx - position_x = x - glyph.height - glyph.dy + y_offset - - if self.label_type == "DWR": - if y == 0: - if top is None: - top = -glyph.dx - top = min(top, -glyph.dx) - if x == 0: - left = min(left, -glyph.dy) - left = min(left, x, x - glyph.dy - y_offset) - bottom = max(bottom, y + glyph.width + glyph.dx, y + glyph.shift_x) - right = max(right, x + glyph.height) - position_y = y + glyph.dx - position_x = x + glyph.dy - y_offset - + left = min(left, glyph.dx) + if y == 0: # first line, find the Ascender height + top = min(top, -glyph.height - glyph.dy + self._y_offset) + bottom = max(bottom, y - glyph.dy + self._y_offset) + position_y = y - glyph.height - glyph.dy + self._y_offset + position_x = x + glyph.dx if glyph.width > 0 and glyph.height > 0: try: # pylint: disable=unexpected-keyword-arg @@ -385,60 +285,27 @@ def _update_text( x=position_x, y=position_y, ) - - if self.label_type == "UPR": - face.transpose_xy = True - face.flip_x = True - if self.label_type == "DWR": - face.transpose_xy = True - face.flip_y = True - if tilegrid_count < len(self.local_group): self.local_group[tilegrid_count] = face else: self.local_group.append(face) tilegrid_count += 1 - if self.label_type == "RTL": - x = x - glyph.shift_x - if self.label_type == "TTB": - if glyph.height < 2: - y = y + glyph.shift_x - else: - y = y + glyph.height + 1 - if self.label_type == "UPR": - y = y - glyph.shift_x - if self.label_type == "DWR": - y = y + glyph.shift_x - if self.label_type == "LTR": - x = x + glyph.shift_x + x += glyph.shift_x i += 1 + # Remove the rest - if self.label_type == "LTR" and left is None: + if left is None: left = 0 - if self.label_type == "RTL" and right is None: - right = 0 - if self.label_type == "TTB" and top is None: - top = 0 while len(self.local_group) > tilegrid_count: # i: self.local_group.pop() - # pylint: disable=invalid-unary-operand-type - if self.label_type == "RTL": - self._bounding_box = (-left, top, left - right, bottom - top) - if self.label_type == "TTB": - self._bounding_box = (left, top, right - left, bottom - top) - if self.label_type == "UPR": - self._bounding_box = (left, top, right, bottom - top) - if self.label_type == "DWR": - self._bounding_box = (left, top, right, bottom - top) - if self.label_type == "LTR": - self._bounding_box = (left, top, right - left, bottom - top) - self._text = new_text + self._bounding_box = (left, top, right - left, bottom - top) + if self.background_color is not None: self._update_background_color(self._background_color) - def _reset_text(self, new_text: str) -> None: + def _reset_text(self, new_text): new_text = self._tab_text.join(new_text.split("\t")) try: current_anchored_position = self.anchored_position @@ -447,7 +314,7 @@ def _reset_text(self, new_text: str) -> None: except RuntimeError as run_error: raise RuntimeError("Text length exceeds max_glyphs") from run_error - def _set_font(self, new_font) -> None: + def _set_font(self, new_font): old_text = self._text current_anchored_position = self.anchored_position self._text = "" @@ -456,9 +323,9 @@ def _set_font(self, new_font) -> None: self._update_text(str(old_text)) self.anchored_position = current_anchored_position - def _set_line_spacing(self, new_line_spacing: float) -> None: + def _set_line_spacing(self, new_line_spacing): self._line_spacing = new_line_spacing self.text = self._text # redraw the box - def _set_text(self, new_text: str, scale: int) -> None: + def _set_text(self, new_text, scale): self._reset_text(new_text) From d977b14fefaf444a1234a5e2728b20fda0a78fee Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 10 Mar 2021 02:01:27 -0500 Subject: [PATCH 3/8] __init__.py force push --- adafruit_display_text/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_display_text/__init__.py b/adafruit_display_text/__init__.py index 56133ce..bc55500 100644 --- a/adafruit_display_text/__init__.py +++ b/adafruit_display_text/__init__.py @@ -187,7 +187,7 @@ class LabelBase(Group): tab character :param: str label_direction: string defining the label text orientation. There are 5 configurations possibles ``LTR``:Left-To-Right ``RTL``:Right-To-Left - ``TTB``:TTB Top-To-Bottom ``UPR``:Upwards ``DWR``:Downwards. It defaults to ``LTR`` """ + ``TTB``:TTB Top-To-Bottom ``UPR``:Upwards ``DWR``:Downwards. It defaults to ``LTR``""" # pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments def __init__( From f6d19be7c098d2920332d452dd75461bd3427131 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 10 Mar 2021 15:17:43 -0500 Subject: [PATCH 4/8] Corrections on docstrings. --- adafruit_display_text/__init__.py | 10 +++++----- adafruit_display_text/bitmap_label.py | 4 ++-- adafruit_display_text/label.py | 7 +++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/adafruit_display_text/__init__.py b/adafruit_display_text/__init__.py index bc55500..d1c1b27 100644 --- a/adafruit_display_text/__init__.py +++ b/adafruit_display_text/__init__.py @@ -180,14 +180,14 @@ class LabelBase(Group): :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. + :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 - :param: (int,str) tab_replacement: tuple with tab character replace information. When + :param (int,str) tab_replacement: tuple with tab character replace information. When (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by tab character - :param: str label_direction: string defining the label text orientation. There are 5 - configurations possibles ``LTR``:Left-To-Right ``RTL``:Right-To-Left - ``TTB``:TTB Top-To-Bottom ``UPR``:Upwards ``DWR``:Downwards. It defaults to ``LTR``""" + :param str label_direction: string defining the label text orientation. There are 5 + configurations possibles ``LTR``-Left-To-Right ``RTL``-Right-To-Left + ``TTB``-Top-To-Bottom ``UPR``-Upwards ``DWR``-Downwards. It defaults to ``LTR``""" # pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments def __init__( diff --git a/adafruit_display_text/bitmap_label.py b/adafruit_display_text/bitmap_label.py index 6fda123..71863fa 100755 --- a/adafruit_display_text/bitmap_label.py +++ b/adafruit_display_text/bitmap_label.py @@ -72,9 +72,9 @@ class Label(LabelBase): :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. + :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 - :param: (int,str) tab_replacement: tuple with tab character replace information. When + :param (int,str) tab_replacement: tuple with tab character replace information. When (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by tab character""" diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 5751fc3..2d8ea9f 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -64,9 +64,12 @@ class Label(LabelBase): :param int scale: Integer value of the pixel scaling :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 - :param: (int,str) tab_replacement: tuple with tab character replace information. When + :param (int,str) tab_replacement: tuple with tab character replace information. When (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by - tab character""" + tab character + :param str label_direction: string defining the label text orientation. There are 5 + configurations possibles ``LTR``-Left-To-Right ``RTL``-Right-To-Left + ``TTB``-Top-To-Bottom ``UPR``-Upwards ``DWR``-Downwards. It defaults to ``LTR``""" # pylint: disable=too-many-instance-attributes, too-many-locals # This has a lot of getters/setters, maybe it needs cleanup. From f61e313d94ce16d6082ed792e9b0ab6ae3ab176c Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Sun, 14 Mar 2021 13:02:37 -0400 Subject: [PATCH 5/8] rebasing with the main branch --- adafruit_display_text/label.py | 201 +++++++++++++++++++++++++++------ 1 file changed, 167 insertions(+), 34 deletions(-) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 872e3d0..8884de3 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -125,6 +125,7 @@ def __init__(self, font, **kwargs) -> None: self._padding_left = kwargs.get("padding_left", 0) self._padding_right = kwargs.get("padding_right", 0) self.base_alignment = kwargs.get("base_alignment", False) + self.label_type = kwargs.get("label_direction", "LTR") if text is not None: self._update_text(str(text)) @@ -139,7 +140,6 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: :param y_offset: int y pixel bottom coordinate for the background_box""" left = self._bounding_box[0] - if self._background_tight: # draw a tight bounding box box_width = self._bounding_box[2] box_height = self._bounding_box[3] @@ -149,14 +149,33 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: else: # draw a "loose" bounding box to include any ascenders/descenders. ascent, descent = self._get_ascent_descent() - box_width = self._bounding_box[2] + self._padding_left + self._padding_right - x_box_offset = -self._padding_left - box_height = ( - (ascent + descent) - + int((lines - 1) * self.height * self._line_spacing) - + self._padding_top - + self._padding_bottom - ) + if ( + self.label_type == "UPR" + or self.label_type == "DWR" + or self.label_type == "TTB" + ): + box_height = ( + self._bounding_box[3] + self._padding_top + self._padding_bottom + ) + x_box_offset = -self._padding_bottom + box_width = ( + (ascent + descent) + + int((lines - 1) * self.width * self._line_spacing) + + self._padding_left + + self._padding_right + ) + else: + box_width = ( + self._bounding_box[2] + self._padding_left + self._padding_right + ) + x_box_offset = -self._padding_left + box_height = ( + (ascent + descent) + + int((lines - 1) * self.height * self._line_spacing) + + self._padding_top + + self._padding_bottom + ) + if self.base_alignment: y_box_offset = -ascent - self._padding_top else: @@ -165,17 +184,31 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: box_width = max(0, box_width) # remove any negative values box_height = max(0, box_height) # remove any negative values + if self.label_type == "UPR": + movx = left + x_box_offset + movy = -box_height - x_box_offset + elif self.label_type == "DWR": + movx = left + x_box_offset + movy = x_box_offset + elif self.label_type == "TTB": + movx = left + x_box_offset + movy = x_box_offset + else: + movx = left + x_box_offset + movy = y_box_offset + background_bitmap = displayio.Bitmap(box_width, box_height, 1) tile_grid = displayio.TileGrid( background_bitmap, pixel_shader=self._background_palette, - x=left + x_box_offset, - y=y_box_offset, + x=movx, + y=movy, ) + return tile_grid - def _update_background_color(self, new_color): + def _update_background_color(self, new_color: int) -> None: """Private class function that allows updating the font box background color :param new_color: int color as an RGB hex number.""" @@ -231,8 +264,8 @@ def _update_background_color(self, new_color): self._added_background_tilegrid = False def _update_text( - self, new_text - ): # pylint: disable=too-many-locals ,too-many-branches, too-many-statements + self, new_text: str + ) -> None: # pylint: disable=too-many-locals ,too-many-branches, too-many-statements x = 0 y = 0 if self._added_background_tilegrid: @@ -245,8 +278,15 @@ def _update_text( else: self._y_offset = self._get_ascent() // 2 - right = top = bottom = 0 - left = None + if self.label_type == "RTL": + left = top = bottom = 0 + right = None + elif self.label_type == "LTR": + right = top = bottom = 0 + left = None + else: + top = right = left = 0 + bottom = 0 for character in new_text: if character == "\n": @@ -256,17 +296,74 @@ def _update_text( glyph = self._font.get_glyph(ord(character)) if not glyph: continue - right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) - if x == 0: - if left is None: - left = glyph.dx + + if self.label_type == "LTR" or self.label_type == "RTL": + bottom = max(bottom, y - glyph.dy + y_offset) + if y == 0: # first line, find the Ascender height + top = min(top, -glyph.height - glyph.dy + y_offset) + position_y = y - glyph.height - glyph.dy + y_offset + + if self.label_type == "LTR": + right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) + if x == 0: + if left is None: + left = glyph.dx + else: + left = min(left, glyph.dx) + position_x = x + glyph.dx else: - left = min(left, glyph.dx) - if y == 0: # first line, find the Ascender height - top = min(top, -glyph.height - glyph.dy + self._y_offset) - bottom = max(bottom, y - glyph.dy + self._y_offset) - position_y = y - glyph.height - glyph.dy + self._y_offset - position_x = x + glyph.dx + left = max( + left, abs(x) + glyph.shift_x, abs(x) + glyph.width + glyph.dx + ) + if x == 0: + if right is None: + right = glyph.dx + else: + right = max(right, glyph.dx) + position_x = x - glyph.width + + if self.label_type == "TTB": + if x == 0: + if left is None: + left = glyph.dx + else: + left = min(left, glyph.dx) + if y == 0: + top = min(top, -glyph.dy) + + bottom = max(bottom, y + glyph.height, y + glyph.height + glyph.dy) + right = max( + right, x + glyph.width + glyph.dx, x + glyph.shift_x + glyph.dx + ) + position_y = y + glyph.dy + position_x = x - glyph.width // 2 + y_offset + + if self.label_type == "UPR": + if x == 0: + if bottom is None: + bottom = -glyph.dx + + if y == 0: # first line, find the Ascender height + bottom = min(bottom, -glyph.dy) + left = min(left, x - glyph.height + y_offset) + top = min(top, y - glyph.width - glyph.dx, y - glyph.shift_x) + right = max(right, x + glyph.height, x + glyph.height - glyph.dy) + position_y = y - glyph.width - glyph.dx + position_x = x - glyph.height - glyph.dy + y_offset + + if self.label_type == "DWR": + if y == 0: + if top is None: + top = -glyph.dx + top = min(top, -glyph.dx) + if x == 0: + left = min(left, -glyph.dy) + left = min(left, x, x - glyph.dy - y_offset) + bottom = max(bottom, y + glyph.width + glyph.dx, y + glyph.shift_x) + right = max(right, x + glyph.height) + position_y = y + glyph.dx + position_x = x + glyph.dy - y_offset + if glyph.width > 0 and glyph.height > 0: try: # pylint: disable=unexpected-keyword-arg @@ -288,27 +385,63 @@ def _update_text( x=position_x, y=position_y, ) + + if self.label_type == "UPR": + face.transpose_xy = True + face.flip_x = True + if self.label_type == "DWR": + face.transpose_xy = True + face.flip_y = True + if tilegrid_count < len(self.local_group): self.local_group[tilegrid_count] = face else: self.local_group.append(face) tilegrid_count += 1 - x += glyph.shift_x + + if self.label_type == "RTL": + x = x - glyph.shift_x + if self.label_type == "TTB": + if glyph.height < 2: + y = y + glyph.shift_x + else: + y = y + glyph.height + 1 + if self.label_type == "UPR": + y = y - glyph.shift_x + if self.label_type == "DWR": + y = y + glyph.shift_x + if self.label_type == "LTR": + x = x + glyph.shift_x + i += 1 - # Remove the rest - if left is None: + if self.label_type == "LTR" and left is None: left = 0 + if self.label_type == "RTL" and right is None: + right = 0 + if self.label_type == "TTB" and top is None: + top = 0 while len(self.local_group) > tilegrid_count: # i: self.local_group.pop() + + if self.label_type == "RTL": + self._bounding_box = (-left, top, left - right, bottom - top) + if self.label_type == "TTB": + self._bounding_box = (left, top, right - left, bottom - top) + if self.label_type == "UPR": + self._bounding_box = (left, top, right, bottom - top) + if self.label_type == "DWR": + self._bounding_box = (left, top, right, bottom - top) + if self.label_type == "LTR": + self._bounding_box = (left, top, right - left, bottom - top) + self._text = new_text - self._bounding_box = (left, top, right - left, bottom - top) if self.background_color is not None: self._update_background_color(self._background_color) - def _reset_text(self, new_text): + def _reset_text(self, new_text: str) -> None: new_text = self._tab_text.join(new_text.split("\t")) try: current_anchored_position = self.anchored_position @@ -317,7 +450,7 @@ def _reset_text(self, new_text): except RuntimeError as run_error: raise RuntimeError("Text length exceeds max_glyphs") from run_error - def _set_font(self, new_font): + def _set_font(self, new_font) -> None: old_text = self._text current_anchored_position = self.anchored_position self._text = "" @@ -326,11 +459,11 @@ def _set_font(self, new_font): self._update_text(str(old_text)) self.anchored_position = current_anchored_position - def _set_line_spacing(self, new_line_spacing): + def _set_line_spacing(self, new_line_spacing: float) -> None: self._line_spacing = new_line_spacing self.text = self._text # redraw the box - def _set_text(self, new_text, scale): + def _set_text(self, new_text: str, scale: int) -> None: self._reset_text(new_text) def _set_background_color(self, new_color): From db44aa082810512a17105605f626ce36932914a3 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Sun, 14 Mar 2021 13:21:01 -0400 Subject: [PATCH 6/8] slef_y_offset and pylint corrections --- adafruit_display_text/label.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 8884de3..2ae45a9 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -205,7 +205,6 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: y=movy, ) - return tile_grid def _update_background_color(self, new_color: int) -> None: @@ -258,11 +257,12 @@ def _update_background_color(self, new_color: int) -> None: self._bounding_box[3] + self._padding_top + self._padding_bottom > 0 ) ): - self.local_group[0] = self._create_background_box(lines, y_offset) + self.local_group[0] = self._create_background_box(lines, self._y_offset) else: # delete the existing bitmap self.local_group.pop(0) self._added_background_tilegrid = False + # pylint: disable = too-many-branches, too-many-statements def _update_text( self, new_text: str ) -> None: # pylint: disable=too-many-locals ,too-many-branches, too-many-statements @@ -298,10 +298,10 @@ def _update_text( continue if self.label_type == "LTR" or self.label_type == "RTL": - bottom = max(bottom, y - glyph.dy + y_offset) + bottom = max(bottom, y - glyph.dy + self._y_offset) if y == 0: # first line, find the Ascender height - top = min(top, -glyph.height - glyph.dy + y_offset) - position_y = y - glyph.height - glyph.dy + y_offset + top = min(top, -glyph.height - glyph.dy + self._y_offset) + position_y = y - glyph.height - glyph.dy + self._y_offset if self.label_type == "LTR": right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) @@ -336,7 +336,7 @@ def _update_text( right, x + glyph.width + glyph.dx, x + glyph.shift_x + glyph.dx ) position_y = y + glyph.dy - position_x = x - glyph.width // 2 + y_offset + position_x = x - glyph.width // 2 + self._y_offset if self.label_type == "UPR": if x == 0: @@ -345,11 +345,11 @@ def _update_text( if y == 0: # first line, find the Ascender height bottom = min(bottom, -glyph.dy) - left = min(left, x - glyph.height + y_offset) + left = min(left, x - glyph.height + self._y_offset) top = min(top, y - glyph.width - glyph.dx, y - glyph.shift_x) right = max(right, x + glyph.height, x + glyph.height - glyph.dy) position_y = y - glyph.width - glyph.dx - position_x = x - glyph.height - glyph.dy + y_offset + position_x = x - glyph.height - glyph.dy + self._y_offset if self.label_type == "DWR": if y == 0: @@ -358,11 +358,11 @@ def _update_text( top = min(top, -glyph.dx) if x == 0: left = min(left, -glyph.dy) - left = min(left, x, x - glyph.dy - y_offset) + left = min(left, x, x - glyph.dy - self._y_offset) bottom = max(bottom, y + glyph.width + glyph.dx, y + glyph.shift_x) right = max(right, x + glyph.height) position_y = y + glyph.dx - position_x = x + glyph.dy - y_offset + position_x = x + glyph.dy - self._y_offset if glyph.width > 0 and glyph.height > 0: try: @@ -424,7 +424,7 @@ def _update_text( while len(self.local_group) > tilegrid_count: # i: self.local_group.pop() - + # pylint: disable=invalid-unary-operand-type if self.label_type == "RTL": self._bounding_box = (-left, top, left - right, bottom - top) if self.label_type == "TTB": From 2865d414ed1b4d2f07518671d4f10dc444b773d1 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Mon, 15 Mar 2021 05:12:26 -0400 Subject: [PATCH 7/8] variable change name to self._line_direction. Setter and getter changes. Error checking in both initial setup and setter module. --- adafruit_display_text/__init__.py | 21 ++++++++++ adafruit_display_text/label.py | 65 +++++++++++++++++-------------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/adafruit_display_text/__init__.py b/adafruit_display_text/__init__.py index 0b21c3b..5d3edb0 100644 --- a/adafruit_display_text/__init__.py +++ b/adafruit_display_text/__init__.py @@ -230,6 +230,11 @@ def __init__( self.local_group = None self._text = text + + if label_direction not in ["LTR", "RTL", "UPR", "DWR", "TTB"]: + raise RuntimeError("Please provide a valid text direction") + self._label_direction = label_direction + self.baseline = -1.0 self.base_alignment = base_alignment @@ -388,3 +393,19 @@ def _set_line_spacing(self, new_line_spacing: float) -> None: @line_spacing.setter def line_spacing(self, new_line_spacing: float) -> None: self._set_line_spacing(new_line_spacing) + + @property + def label_direction(self) -> str: + """Set the text direction of the label""" + return self._label_direction + + def _set_label_direction(self, new_label_direction: str) -> None: + # subclass should override this. + pass + + @label_direction.setter + def label_direction(self, new_label_direction: str) -> None: + """Set the text direction of the label""" + if new_label_direction not in ["LTR", "RTL", "UPR", "DWR", "TTB"]: + raise RuntimeError("Please provide a valid text direction") + self._set_label_direction(new_label_direction) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 2ae45a9..da1b266 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -125,7 +125,7 @@ def __init__(self, font, **kwargs) -> None: self._padding_left = kwargs.get("padding_left", 0) self._padding_right = kwargs.get("padding_right", 0) self.base_alignment = kwargs.get("base_alignment", False) - self.label_type = kwargs.get("label_direction", "LTR") + self._label_direction = kwargs.get("label_direction", "LTR") if text is not None: self._update_text(str(text)) @@ -150,9 +150,9 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: ascent, descent = self._get_ascent_descent() if ( - self.label_type == "UPR" - or self.label_type == "DWR" - or self.label_type == "TTB" + self._label_direction == "UPR" + or self._label_direction == "DWR" + or self._label_direction == "TTB" ): box_height = ( self._bounding_box[3] + self._padding_top + self._padding_bottom @@ -184,13 +184,13 @@ def _create_background_box(self, lines: int, y_offset: int) -> None: box_width = max(0, box_width) # remove any negative values box_height = max(0, box_height) # remove any negative values - if self.label_type == "UPR": + if self._label_direction == "UPR": movx = left + x_box_offset movy = -box_height - x_box_offset - elif self.label_type == "DWR": + elif self._label_direction == "DWR": movx = left + x_box_offset movy = x_box_offset - elif self.label_type == "TTB": + elif self._label_direction == "TTB": movx = left + x_box_offset movy = x_box_offset else: @@ -278,10 +278,10 @@ def _update_text( else: self._y_offset = self._get_ascent() // 2 - if self.label_type == "RTL": + if self._label_direction== "RTL": left = top = bottom = 0 right = None - elif self.label_type == "LTR": + elif self._label_direction == "LTR": right = top = bottom = 0 left = None else: @@ -297,13 +297,13 @@ def _update_text( if not glyph: continue - if self.label_type == "LTR" or self.label_type == "RTL": + if self._label_direction == "LTR" or self._label_direction == "RTL": bottom = max(bottom, y - glyph.dy + self._y_offset) if y == 0: # first line, find the Ascender height top = min(top, -glyph.height - glyph.dy + self._y_offset) position_y = y - glyph.height - glyph.dy + self._y_offset - if self.label_type == "LTR": + if self._label_direction == "LTR": right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx) if x == 0: if left is None: @@ -322,7 +322,7 @@ def _update_text( right = max(right, glyph.dx) position_x = x - glyph.width - if self.label_type == "TTB": + if self._label_direction == "TTB": if x == 0: if left is None: left = glyph.dx @@ -338,7 +338,7 @@ def _update_text( position_y = y + glyph.dy position_x = x - glyph.width // 2 + self._y_offset - if self.label_type == "UPR": + if self._label_direction == "UPR": if x == 0: if bottom is None: bottom = -glyph.dx @@ -351,7 +351,7 @@ def _update_text( position_y = y - glyph.width - glyph.dx position_x = x - glyph.height - glyph.dy + self._y_offset - if self.label_type == "DWR": + if self._label_direction == "DWR": if y == 0: if top is None: top = -glyph.dx @@ -386,10 +386,10 @@ def _update_text( y=position_y, ) - if self.label_type == "UPR": + if self._label_direction == "UPR": face.transpose_xy = True face.flip_x = True - if self.label_type == "DWR": + if self._label_direction == "DWR": face.transpose_xy = True face.flip_y = True @@ -399,41 +399,41 @@ def _update_text( self.local_group.append(face) tilegrid_count += 1 - if self.label_type == "RTL": + if self._label_direction == "RTL": x = x - glyph.shift_x - if self.label_type == "TTB": + if self._label_direction == "TTB": if glyph.height < 2: y = y + glyph.shift_x else: y = y + glyph.height + 1 - if self.label_type == "UPR": + if self._label_direction == "UPR": y = y - glyph.shift_x - if self.label_type == "DWR": + if self._label_direction == "DWR": y = y + glyph.shift_x - if self.label_type == "LTR": + if self._label_direction == "LTR": x = x + glyph.shift_x i += 1 - if self.label_type == "LTR" and left is None: + if self._label_direction == "LTR" and left is None: left = 0 - if self.label_type == "RTL" and right is None: + if self._label_direction == "RTL" and right is None: right = 0 - if self.label_type == "TTB" and top is None: + if self._label_direction == "TTB" and top is None: top = 0 while len(self.local_group) > tilegrid_count: # i: self.local_group.pop() # pylint: disable=invalid-unary-operand-type - if self.label_type == "RTL": + if self._label_direction == "RTL": self._bounding_box = (-left, top, left - right, bottom - top) - if self.label_type == "TTB": + if self._label_direction == "TTB": self._bounding_box = (left, top, right - left, bottom - top) - if self.label_type == "UPR": + if self._label_direction == "UPR": self._bounding_box = (left, top, right, bottom - top) - if self.label_type == "DWR": + if self._label_direction == "DWR": self._bounding_box = (left, top, right, bottom - top) - if self.label_type == "LTR": + if self._label_direction == "LTR": self._bounding_box = (left, top, right - left, bottom - top) self._text = new_text @@ -466,5 +466,10 @@ def _set_line_spacing(self, new_line_spacing: float) -> None: def _set_text(self, new_text: str, scale: int) -> None: self._reset_text(new_text) - def _set_background_color(self, new_color): + def _set_background_color(self, new_color: int) -> None: self._update_background_color(new_color) + + def _set_label_direction(self, new_line_direction: str) -> None: + self._label_direction = new_line_direction + old_text = self._text + self._update_text(str(old_text)) From 343ce75834d57bfaf74d28135b81cef23ae12050 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Mon, 15 Mar 2021 05:25:05 -0400 Subject: [PATCH 8/8] variable correction in setter. pylint and black verifications --- adafruit_display_text/label.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index da1b266..4e7373a 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -278,7 +278,7 @@ def _update_text( else: self._y_offset = self._get_ascent() // 2 - if self._label_direction== "RTL": + if self._label_direction == "RTL": left = top = bottom = 0 right = None elif self._label_direction == "LTR": @@ -469,7 +469,7 @@ def _set_text(self, new_text: str, scale: int) -> None: def _set_background_color(self, new_color: int) -> None: self._update_background_color(new_color) - def _set_label_direction(self, new_line_direction: str) -> None: - self._label_direction = new_line_direction + def _set_label_direction(self, new_label_direction: str) -> None: + self._label_direction = new_label_direction old_text = self._text self._update_text(str(old_text))