From d5aa61dcc0ee0df783b407713dad626161b7026d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 23 Nov 2021 13:13:37 -0600 Subject: [PATCH 001/132] update rtd py version --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 95ec218..1335112 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -9,7 +9,7 @@ version: 2 python: - version: "3.6" + version: "3.7" install: - requirements: docs/requirements.txt - requirements: requirements.txt From f53b4b28597df456f134b5dd3cd429a66e35c480 Mon Sep 17 00:00:00 2001 From: GingerIndustries <75683114+GingerIndustries@users.noreply.github.com> Date: Wed, 24 Nov 2021 16:25:20 -0500 Subject: [PATCH 002/132] Update grid_layout.py Added the ability to change the divider line color --- adafruit_displayio_layout/layouts/grid_layout.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index e63d6ac..bbdcfc3 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -59,6 +59,7 @@ def __init__( divider_lines=False, h_divider_line_rows=None, v_divider_line_cols=None, + divider_line_color=0xFFFFFF, ): super().__init__(x=x, y=y) self.x = x @@ -70,6 +71,7 @@ def __init__( self._cell_content_list = [] self._divider_lines = [] + self._divider_color = divider_line_color self.h_divider_line_rows = h_divider_line_rows self.v_divider_line_cols = v_divider_line_cols @@ -164,8 +166,8 @@ def _layout_cells(self): if self._divider_lines_enabled: palette = displayio.Palette(2) - palette[0] = 0xFFFFFF - palette[1] = 0xFFFFFF + palette[0] = self._divider_color + palette[1] = self._divider_color if not hasattr(cell["content"], "anchor_point"): _bottom_line_loc_y = ( From 03bd012f1fabef9b8e42023a815ed311d50ccaf7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 24 Nov 2021 17:15:21 -0500 Subject: [PATCH 003/132] Pass filename to OnDiskBitmap to avoid closed file problem --- adafruit_displayio_layout/widgets/icon_widget.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/adafruit_displayio_layout/widgets/icon_widget.py b/adafruit_displayio_layout/widgets/icon_widget.py index 1b62dbd..f2fe0fd 100644 --- a/adafruit_displayio_layout/widgets/icon_widget.py +++ b/adafruit_displayio_layout/widgets/icon_widget.py @@ -24,7 +24,7 @@ import terminalio -from displayio import TileGrid, OnDiskBitmap, ColorConverter +from displayio import TileGrid, OnDiskBitmap import adafruit_imageload from adafruit_display_text import bitmap_label from adafruit_displayio_layout.widgets.control import Control @@ -57,14 +57,8 @@ def __init__(self, label_text, icon, on_disk=False, **kwargs): self._icon = icon if on_disk: - with open(self._icon, "rb") as self._file: - image = OnDiskBitmap(self._file) - tile_grid = TileGrid( - image, - pixel_shader=getattr(image, "pixel_shader", ColorConverter()) - # TODO: Once CP6 is no longer supported replace the above line with below. - # tile_grid = TileGrid(image, pixel_shader=image.pixel_shader) - ) + image = OnDiskBitmap(self._icon) + tile_grid = TileGrid(image, pixel_shader=image.pixel_shader) else: image, palette = adafruit_imageload.load(icon) tile_grid = TileGrid(image, pixel_shader=palette) From d0e83e1e3cbc12aab5425a068c089699681b5cd2 Mon Sep 17 00:00:00 2001 From: GingerIndustries <75683114+GingerIndustries@users.noreply.github.com> Date: Fri, 26 Nov 2021 07:31:04 -0500 Subject: [PATCH 004/132] Fixed pylint and added docstring --- adafruit_displayio_layout/layouts/grid_layout.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index bbdcfc3..e3b1a50 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -44,10 +44,12 @@ class GridLayout(displayio.Group): lines above. Row indexes are 0 based. :param Union[tuple, list] v_divider_line_cols: Column indexes to draw divider lines before. Column indexes are 0 based. + :param divider_line_color: The color of the divider lines (in hexadecimal) """ # pylint: disable=too-many-arguments + # pylint: disable=too-many-instance-attributes def __init__( self, x, From abb6c35650dda17e5e6e92062f8f7767e92dccdc Mon Sep 17 00:00:00 2001 From: Randall Bohn Date: Fri, 26 Nov 2021 08:13:43 -0700 Subject: [PATCH 005/132] Handle ImportError in widgets __init__.py If bitmaptools is not available an ImportError is raised. --- adafruit_displayio_layout/widgets/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/widgets/__init__.py b/adafruit_displayio_layout/widgets/__init__.py index ed1bae9..e1e8282 100644 --- a/adafruit_displayio_layout/widgets/__init__.py +++ b/adafruit_displayio_layout/widgets/__init__.py @@ -11,7 +11,7 @@ try: import bitmaptools -except NameError: +except ImportError: pass From c0115d60f683a69782d32ffac2258ebf658b9c5d Mon Sep 17 00:00:00 2001 From: Randall Bohn Date: Fri, 26 Nov 2021 08:15:33 -0700 Subject: [PATCH 006/132] Handle missing bitmaptools in cartesian.py --- adafruit_displayio_layout/widgets/cartesian.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index fa678c6..601e0da 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -33,9 +33,6 @@ try: import bitmaptools -except NameError: - pass -try: from typing import Tuple except ImportError: pass From 3626da3adb3758e174bd4b80ae79e237650f8ac5 Mon Sep 17 00:00:00 2001 From: Randall Bohn Date: Fri, 26 Nov 2021 08:41:50 -0700 Subject: [PATCH 007/132] Try imports in separate blocks As @foamyguy pointed out, you may have one or the other library, both or none. This handles the combinations properly. --- adafruit_displayio_layout/widgets/cartesian.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 601e0da..c914cd9 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -33,6 +33,10 @@ try: import bitmaptools +except ImportError: + pass + +try: from typing import Tuple except ImportError: pass From 6aa9836a06ce10b95d9f2eaa6d59f602afb80072 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 26 Nov 2021 12:52:10 -0600 Subject: [PATCH 008/132] allow missing vectorio --- adafruit_displayio_layout/widgets/__init__.py | 5 +- ...ut_gridlayout_pygame_display_simpletest.py | 6 +- ...ayio_layout_pygame_display_switch_round.py | 83 +++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 examples/displayio_layout_pygame_display_switch_round.py diff --git a/adafruit_displayio_layout/widgets/__init__.py b/adafruit_displayio_layout/widgets/__init__.py index e1e8282..cbc4f01 100644 --- a/adafruit_displayio_layout/widgets/__init__.py +++ b/adafruit_displayio_layout/widgets/__init__.py @@ -7,7 +7,10 @@ ======================= """ -import vectorio +try: + import vectorio +except ImportError: + pass try: import bitmaptools diff --git a/examples/displayio_layout_gridlayout_pygame_display_simpletest.py b/examples/displayio_layout_gridlayout_pygame_display_simpletest.py index 447d75a..207faf8 100644 --- a/examples/displayio_layout_gridlayout_pygame_display_simpletest.py +++ b/examples/displayio_layout_gridlayout_pygame_display_simpletest.py @@ -2,8 +2,10 @@ # # SPDX-License-Identifier: MIT """ -Make green and purple rectangles and a -"Hello World" label. Displayed with Blinka_Displayio_PyGameDisplay +Make a GridLayout with some Labels in it's cells. +Displayed with Blinka_Displayio_PyGameDisplay + +Requires: https://github.com/FoamyGuy/Blinka_Displayio_PyGameDisplay """ import displayio import terminalio diff --git a/examples/displayio_layout_pygame_display_switch_round.py b/examples/displayio_layout_pygame_display_switch_round.py new file mode 100644 index 0000000..e6f4cd6 --- /dev/null +++ b/examples/displayio_layout_pygame_display_switch_round.py @@ -0,0 +1,83 @@ +# SPDX-FileCopyrightText: 2021 Tim C +# +# SPDX-License-Identifier: MIT +""" +Make a GridLayout with some Labels in it's cells. +Displayed with Blinka_Displayio_PyGameDisplay + +Requires: https://github.com/FoamyGuy/Blinka_Displayio_PyGameDisplay +""" +import displayio +import pygame +from blinka_displayio_pygamedisplay import PyGameDisplay +from adafruit_displayio_layout.widgets.switch_round import SwitchRound as Switch + + +# Make the display context. Change size if you want +display = PyGameDisplay(width=320, height=240) + +# Make the display context +main_group = displayio.Group(max_size=10) +display.show(main_group) + +switch_x = 30 +switch_y = 30 +switch_radius = 20 + +switch_fill_color_off = (200, 44, 200) +switch_fill_color_on = (0, 100, 0) + +switch_outline_color_off = (30, 30, 30) +switch_outline_color_on = (0, 60, 0) + +background_color_off = (255, 255, 255) +background_color_on = (90, 255, 90) + +background_outline_color_off = background_color_off +background_outline_color_on = background_color_on + +switch_width = 4 * switch_radius # This is a good aspect ratio to start with + +switch_stroke = 2 # Width of the outlines (in pixels) +text_stroke = switch_stroke # width of text lines +touch_padding = 0 # Additional boundary around widget that will accept touch input + +animation_time = 0.2 # time for switch to display change (in seconds). + # animation_time=0.15 is a good starting point +display_text = True # show the text (0/1) + +# initialize state variables +switch_value = False +switch_value = True + +my_switch = Switch( + x=switch_x, + y=switch_y, + height=switch_radius * 2, + fill_color_off=switch_fill_color_off, + fill_color_on=switch_fill_color_on, + outline_color_off=switch_outline_color_off, + outline_color_on=switch_outline_color_on, + background_color_off=background_color_off, + background_color_on=background_color_on, + background_outline_color_off=background_outline_color_off, + background_outline_color_on=background_outline_color_on, + switch_stroke=switch_stroke, + display_button_text=display_text, + touch_padding=10, + animation_time=animation_time, + value=False, +) + + +main_group.append(my_switch) +while display.running: + + # get mouse up events + ev = pygame.event.get(eventtype=pygame.MOUSEBUTTONUP) + # proceed events + for event in ev: + pos = pygame.mouse.get_pos() + print(pos) + if my_switch.contains(pos): + my_switch.selected(pos) From bbf600251895a0227c340c2325f82062399d3871 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 26 Nov 2021 12:55:55 -0600 Subject: [PATCH 009/132] code format --- examples/displayio_layout_pygame_display_switch_round.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/displayio_layout_pygame_display_switch_round.py b/examples/displayio_layout_pygame_display_switch_round.py index e6f4cd6..f0e0d7a 100644 --- a/examples/displayio_layout_pygame_display_switch_round.py +++ b/examples/displayio_layout_pygame_display_switch_round.py @@ -43,7 +43,7 @@ touch_padding = 0 # Additional boundary around widget that will accept touch input animation_time = 0.2 # time for switch to display change (in seconds). - # animation_time=0.15 is a good starting point +# animation_time=0.15 is a good starting point display_text = True # show the text (0/1) # initialize state variables From 7e75c94dd8db6919f0879786ec316073ea38b75c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 28 Nov 2021 13:40:27 -0600 Subject: [PATCH 010/132] add cell_anchor_point feature --- .../layouts/grid_layout.py | 165 +++++++++++++++--- 1 file changed, 137 insertions(+), 28 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index e3b1a50..35dd1e3 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -22,6 +22,12 @@ https://github.com/adafruit/circuitpython/releases """ +try: + # Used only for typing + from typing import Tuple +except ImportError: + pass + import math import displayio @@ -45,6 +51,8 @@ class GridLayout(displayio.Group): :param Union[tuple, list] v_divider_line_cols: Column indexes to draw divider lines before. Column indexes are 0 based. :param divider_line_color: The color of the divider lines (in hexadecimal) + :param tuple cell_anchor_point: Anchor point used within every cell. Needs to + be a tuple containing two floats between 0.0 and 1.0 """ @@ -62,6 +70,7 @@ def __init__( h_divider_line_rows=None, v_divider_line_cols=None, divider_line_color=0xFFFFFF, + cell_anchor_point=(0.0, 0.0), ): super().__init__(x=x, y=y) self.x = x @@ -71,6 +80,7 @@ def __init__( self.grid_size = grid_size self.cell_padding = cell_padding self._cell_content_list = [] + self._cell_anchor_point = cell_anchor_point self._divider_lines = [] self._divider_color = divider_line_color @@ -114,18 +124,19 @@ def _layout_cells(self): grid_position_x = cell["grid_position"][0] grid_position_y = cell["grid_position"][1] - button_size_x = cell["cell_size"][0] - button_size_y = cell["cell_size"][1] + content_cell_size_x = cell["cell_size"][0] + content_cell_size_y = cell["cell_size"][1] _measured_width = ( - math.ceil(button_size_x * self._width / grid_size_x) + math.ceil(content_cell_size_x * self._width / grid_size_x) - 2 * self.cell_padding ) _measured_height = ( - math.ceil(button_size_y * self._height / grid_size_y) + math.ceil(content_cell_size_y * self._height / grid_size_y) - 2 * self.cell_padding ) + if hasattr(cell["content"], "resize"): # if it has resize function cell["content"].resize( @@ -150,18 +161,24 @@ def _layout_cells(self): cell["content"].x = ( int(grid_position_x * self._width / grid_size_x) + self.cell_padding + + int(cell["cell_anchor_point"][0] * _measured_width) + - int(cell["content"].width * cell["cell_anchor_point"][0]) ) cell["content"].y = ( int(grid_position_y * self._height / grid_size_y) + self.cell_padding + + int(cell["cell_anchor_point"][1] * _measured_height) + - int(cell["content"].height * cell["cell_anchor_point"][1]) ) else: - cell["content"].anchor_point = (0, 0) + cell["content"].anchor_point = cell["cell_anchor_point"] cell["content"].anchored_position = ( int(grid_position_x * self._width / grid_size_x) - + self.cell_padding, + + self.cell_padding + + (cell["cell_anchor_point"][0] * _measured_width), int(grid_position_y * self._height / grid_size_y) - + self.cell_padding, + + self.cell_padding + + (cell["cell_anchor_point"][1] * _measured_height), ) self.append(cell["content"]) @@ -173,42 +190,84 @@ def _layout_cells(self): if not hasattr(cell["content"], "anchor_point"): _bottom_line_loc_y = ( - cell["content"].y + _measured_height + self.cell_padding - ) - 1 - _bottom_line_loc_x = cell["content"].x - self.cell_padding + (cell["content"].y + _measured_height + self.cell_padding) + - 1 + - int(cell["cell_anchor_point"][1] * _measured_height) + + int(cell["content"].height * cell["cell_anchor_point"][1]) + ) - _top_line_loc_y = cell["content"].y - self.cell_padding - _top_line_loc_x = cell["content"].x - self.cell_padding + _bottom_line_loc_x = ( + cell["content"].x + - self.cell_padding + - int(cell["cell_anchor_point"][0] * _measured_width) + + int(cell["content"].width * cell["cell_anchor_point"][0]) + ) + + _top_line_loc_y = ( + cell["content"].y + - self.cell_padding + - int(cell["cell_anchor_point"][1] * _measured_height) + + int(cell["content"].height * cell["cell_anchor_point"][1]) + ) + + _top_line_loc_x = ( + cell["content"].x + - self.cell_padding + - int(cell["cell_anchor_point"][0] * _measured_width) + + int(cell["content"].width * cell["cell_anchor_point"][0]) + ) + + _right_line_loc_y = ( + cell["content"].y + - self.cell_padding + - int(cell["cell_anchor_point"][1] * _measured_height) + + int(cell["content"].height * cell["cell_anchor_point"][1]) + ) - _right_line_loc_y = cell["content"].y - self.cell_padding _right_line_loc_x = ( - cell["content"].x + _measured_width + self.cell_padding - ) - 1 + (cell["content"].x + _measured_width + self.cell_padding) + - 1 + - int(cell["cell_anchor_point"][0] * _measured_width) + + int(cell["content"].width * cell["cell_anchor_point"][0]) + ) else: _bottom_line_loc_y = ( cell["content"].anchored_position[1] + _measured_height + self.cell_padding + - (cell["cell_anchor_point"][1] * _measured_height) ) - 1 _bottom_line_loc_x = ( - cell["content"].anchored_position[0] - self.cell_padding + cell["content"].anchored_position[0] + - self.cell_padding + - (cell["cell_anchor_point"][0] * _measured_width) ) _top_line_loc_y = ( - cell["content"].anchored_position[1] - self.cell_padding + cell["content"].anchored_position[1] + - self.cell_padding + - (cell["cell_anchor_point"][1] * _measured_height) ) _top_line_loc_x = ( - cell["content"].anchored_position[0] - self.cell_padding + cell["content"].anchored_position[0] + - self.cell_padding + - (cell["cell_anchor_point"][0] * _measured_width) ) _right_line_loc_y = ( - cell["content"].anchored_position[1] - self.cell_padding + cell["content"].anchored_position[1] + - self.cell_padding + - (cell["cell_anchor_point"][1] * _measured_height) ) _right_line_loc_x = ( - cell["content"].anchored_position[0] - + _measured_width - + self.cell_padding - ) - 1 + ( + cell["content"].anchored_position[0] + + _measured_width + + self.cell_padding + ) + - 1 + - (cell["cell_anchor_point"][0] * _measured_width) + ) _horizontal_divider_line = displayio.Shape( _measured_width + (2 * self.cell_padding), @@ -255,8 +314,18 @@ def _layout_cells(self): for line_obj in self._divider_lines: self.remove(line_obj["tilegrid"]) - if grid_position_y == grid_size_y - 1 and ( - grid_position_y + 1 in self.h_divider_line_rows + """ + Only use bottom divider lines on the bottom row. All + other rows rely on top divder lines of the row beneath them. + Add the content_cell_size to the grid_position to account for + areas larger than 1x1 cells. For 1x1 cells this will equal zero + and not change anything. + """ + if ( + grid_position_y + content_cell_size_y - 1 + ) == grid_size_y - 1 and ( + (grid_position_y + content_cell_size_y - 1) + 1 + in self.h_divider_line_rows ): self._divider_lines.append( { @@ -264,6 +333,11 @@ def _layout_cells(self): "tilegrid": _bottom_divider_tilegrid, } ) + + """ + Every cell whose index is in h_divider_line_rows gets + a top divider line. + """ if grid_position_y in self.h_divider_line_rows: self._divider_lines.append( { @@ -271,6 +345,11 @@ def _layout_cells(self): "tilegrid": _top_divider_tilegrid, } ) + + """ + Every cell whose index is in v_divider_line_cols gets + a left divider line. + """ if grid_position_x in self.v_divider_line_cols: self._divider_lines.append( { @@ -278,8 +357,18 @@ def _layout_cells(self): "tilegrid": _left_divider_tilegrid, } ) - if grid_position_x == grid_size_x - 1 and ( - grid_position_x + 1 in self.v_divider_line_cols + """ + Only use right divider lines on the right-most column. All + other columns rely on left divider lines of the column to their + left. Add the content_cell_size to the grid_position to account for + areas larger than 1x1 cells. For 1x1 cells this will equal zero + and not change anything. + """ + if ( + grid_position_x + content_cell_size_x - 1 + ) == grid_size_x - 1 and ( + (grid_position_x + content_cell_size_x - 1) + 1 + in self.v_divider_line_cols ): self._divider_lines.append( { @@ -291,7 +380,9 @@ def _layout_cells(self): for line_obj in self._divider_lines: self.append(line_obj["tilegrid"]) - def add_content(self, cell_content, grid_position, cell_size): + def add_content( + self, cell_content, grid_position, cell_size, cell_anchor_point=None + ): """Add a child to the grid. :param cell_content: the content to add to this cell e.g. label, button, etc... @@ -301,7 +392,14 @@ def add_content(self, cell_content, grid_position, cell_size): :param tuple cell_size: the size and shape that the new cell should occupy. Width and height in cells inside a tuple e.g. (1, 1) :return: None""" + + if cell_anchor_point: + _this_cell_anchor_point = cell_anchor_point + else: + _this_cell_anchor_point = self._cell_anchor_point + sub_view_obj = { + "cell_anchor_point": _this_cell_anchor_point, "content": cell_content, "grid_position": grid_position, "cell_size": cell_size, @@ -326,3 +424,14 @@ def get_cell(self, cell_coordinates): cell_coordinates ) ) + + @property + def cell_size_pixels(self) -> Tuple[int, int]: + """ + Get the size of a 1x1 cell in pixels. Can be useful for manually + re-positioning content within cells. + + :return Tuple[int, int]: A tuple containing the (x, y) size in + pixels of a 1x1 cell in the GridLayout + """ + return (self._width // self.grid_size[0], self._height // self.grid_size[1]) From 9182e129c25af50b912896912f7fb19d45a581f9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 28 Nov 2021 13:44:24 -0600 Subject: [PATCH 011/132] clarify default cell_anchor_point --- adafruit_displayio_layout/layouts/grid_layout.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 35dd1e3..95b922f 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -52,7 +52,8 @@ class GridLayout(displayio.Group): lines before. Column indexes are 0 based. :param divider_line_color: The color of the divider lines (in hexadecimal) :param tuple cell_anchor_point: Anchor point used within every cell. Needs to - be a tuple containing two floats between 0.0 and 1.0 + be a tuple containing two floats between 0.0 and 1.0. Default is (0.0, 0.0) + which will anchor content to the top left of the cell. """ From 710b202ba81ef2088d0a1c9ac49334795b6ecb93 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 28 Nov 2021 14:03:24 -0600 Subject: [PATCH 012/132] fix for sphinx build. add docstring for new arg in add_content() --- adafruit_displayio_layout/layouts/grid_layout.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 95b922f..28c7b50 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -392,6 +392,10 @@ def add_content( x,y coordinates in grid cells. e.g. (1,0) :param tuple cell_size: the size and shape that the new cell should occupy. Width and height in cells inside a tuple e.g. (1, 1) + :param tuple cell_anchor_point: a tuple of floats between 0.0 and 1.0. + If passed, this value will override the cell_anchor_point of the GridLayout + for the single cell having it's content added with this function call. If omitted + then the cell_anchor_point from the GridLayout will be used. :return: None""" if cell_anchor_point: @@ -433,6 +437,6 @@ def cell_size_pixels(self) -> Tuple[int, int]: re-positioning content within cells. :return Tuple[int, int]: A tuple containing the (x, y) size in - pixels of a 1x1 cell in the GridLayout + pixels of a 1x1 cell in the GridLayout """ return (self._width // self.grid_size[0], self._height // self.grid_size[1]) From f2142a23b64b4e096552ac1b0fd1c8d296f48a91 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 28 Nov 2021 14:06:31 -0600 Subject: [PATCH 013/132] remove max_size usage from switch_round example --- examples/displayio_layout_pygame_display_switch_round.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/displayio_layout_pygame_display_switch_round.py b/examples/displayio_layout_pygame_display_switch_round.py index f0e0d7a..63eb69c 100644 --- a/examples/displayio_layout_pygame_display_switch_round.py +++ b/examples/displayio_layout_pygame_display_switch_round.py @@ -17,7 +17,7 @@ display = PyGameDisplay(width=320, height=240) # Make the display context -main_group = displayio.Group(max_size=10) +main_group = displayio.Group() display.show(main_group) switch_x = 30 From a1d19d80425f856d5cc558ca8d80b720854b4d04 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Dec 2021 18:23:31 -0600 Subject: [PATCH 014/132] fix cartesian for new vectorio API --- .../widgets/cartesian.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index c914cd9..6628906 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -314,7 +314,6 @@ def __init__( self._pointer = None self._circle_palette = None - self._pointer_vector_shape = None self.plot_line_point = None @staticmethod @@ -449,18 +448,14 @@ def _draw_ticks(self) -> None: ) def _draw_pointers(self, x: int, y: int) -> None: - self._pointer = vectorio.Circle(self._pointer_radius) - self._circle_palette = displayio.Palette(2) - self._circle_palette.make_transparent(0) - self._circle_palette[1] = self._pointer_color - - self._pointer_vector_shape = vectorio.VectorShape( - shape=self._pointer, - pixel_shader=self._circle_palette, - x=x, - y=y, + + self._circle_palette = displayio.Palette(1) + self._circle_palette[0] = self._pointer_color + self._pointer = vectorio.Circle( + radius=self._pointer_radius, x=x, y=y, pixel_shader=self._circle_palette ) - self.append(self._pointer_vector_shape) + + self.append(self._pointer) def update_pointer(self, x: int, y: int) -> None: """updater_pointer function @@ -480,8 +475,8 @@ def update_pointer(self, x: int, y: int) -> None: self._draw_pointers(local_x, local_y) self._update_line = False else: - self._pointer_vector_shape.x = local_x - self._pointer_vector_shape.y = local_y + self._pointer.x = local_x + self._pointer.y = local_y def _set_plotter_line(self) -> None: self.plot_line_point = [] From c24681e696ac63e22b7bd84c39e860c8ab5a1f06 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 07:43:55 +0100 Subject: [PATCH 015/132] cartesian: fix basic update_line & add example --- .../widgets/cartesian.py | 1 + .../displayio_layout_cartesian_lineplot.py | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 examples/displayio_layout_cartesian_lineplot.py diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 6628906..5955be7 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -508,3 +508,4 @@ def update_line(self, x: int, y: int) -> None: local_y, 1, ) + self.plot_line_point.append((local_x, local_y)) diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py new file mode 100644 index 0000000..192b952 --- /dev/null +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2021 Stefan Krüger +# +# SPDX-License-Identifier: MIT +############################# +""" +This is a basic demonstration of a Cartesian widget for line-ploting +""" + +import time +import board +import displayio +from adafruit_displayio_layout.widgets.cartesian import Cartesian + +# create the display on the PyPortal or Clue or PyBadge(for example) +display = board.DISPLAY +# otherwise change this to setup the display +# for display chip driver and pinout you have (e.g. ILI9341) + +# pybadge display: 160x128 +# Create a Cartesian widget +# https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian +my_plane = Cartesian( + x=30, # x position for the plane + y=2, # y plane position + width=128, # display width + height=105, # display height + xrange=(0, 100), # x range + yrange=(0, 100), # y range +) + +my_group = displayio.Group() +my_group.append(my_plane) +display.show(my_group) # add high level Group to the display + +data = [ + (0, 0), + (1, 10), + (20, 50), + (30, 60), + (40, 40), + (50, 80), + (60, 20), + (70, 60), + (80, 30), + (100, 100), +] + +print("examples/displayio_layout_cartesian_lineplot.py") +for x, y in data: + my_plane.update_line(x, y) + time.sleep(0.5) + print(my_plane.plot_line_point) + +while True: + pass From 5d60353e43c1b07141fab7c8f6835c2a8e07dae8 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 07:52:43 +0100 Subject: [PATCH 016/132] extract local calculation --- .../widgets/cartesian.py | 17 +++++----- .../displayio_layout_cartesian_lineplot.py | 32 +++++++++++++------ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 5955be7..4d92965 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -457,6 +457,13 @@ def _draw_pointers(self, x: int, y: int) -> None: self.append(self._pointer) + def _calc_local_xy(self, x: int, y: int) -> (int, int): + local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x + local_y = ( + int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y + ) + return (local_x, local_y) + def update_pointer(self, x: int, y: int) -> None: """updater_pointer function helper function to update pointer in the plane @@ -465,10 +472,7 @@ def update_pointer(self, x: int, y: int) -> None: :return: None rtype: None """ - local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x - local_y = ( - int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y - ) + local_x, local_y = self._calc_local_xy(x, y) if local_x >= 0 or local_y <= 100: if self._update_line: @@ -489,10 +493,7 @@ def update_line(self, x: int, y: int) -> None: :return: None rtype: None """ - local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x - local_y = ( - int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y - ) + local_x, local_y = self._calc_local_xy(x, y) if x < self._xrange[1] and y < self._yrange[1]: if local_x > 0 or local_y < 100: if self._update_line: diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index 192b952..ba1fd20 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -34,20 +34,34 @@ data = [ (0, 0), - (1, 10), - (20, 50), - (30, 60), + (10, 10), + (20, 20), + (30, 30), (40, 40), - (50, 80), - (60, 20), - (70, 60), - (80, 30), - (100, 100), + (50, 50), + (60, 60), + (70, 70), + (80, 80), + (90, 90), ] +# +# data = [ +# (0, 0), +# (10, 10), +# (20, 50), +# (30, 60), +# (40, 40), +# (50, 80), +# (60, 20), +# (70, 60), +# (80, 30), +# (100, 100), +# ] print("examples/displayio_layout_cartesian_lineplot.py") for x, y in data: - my_plane.update_line(x, y) + # my_plane.update_line(x, y) + my_plane.update_pointer(x, y) time.sleep(0.5) print(my_plane.plot_line_point) From af4c74cf3c1e900f30200d08b6391a54cfe02a41 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 09:44:06 +0100 Subject: [PATCH 017/132] debug _calc_local_xy --- .../widgets/cartesian.py | 8 ++- examples/displayio_layout_cartesian_dev.py | 56 +++++++++++++++++++ .../displayio_layout_cartesian_lineplot.py | 37 ++++-------- 3 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 examples/displayio_layout_cartesian_dev.py diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 4d92965..f6dc6ef 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -389,10 +389,12 @@ def _draw_ticks(self) -> None: if self._subticks: if i in subticks: + # calc subtick_line_height; force min lineheigt to 1. + subtick_line_height = max(1, self._tick_line_height // 2) rectangle_helper( text_dist, self._axes_line_thickness, - self._tick_line_height // 2, + subtick_line_height, 1, self._axesx_bitmap, 1, @@ -458,10 +460,13 @@ def _draw_pointers(self, x: int, y: int) -> None: self.append(self._pointer) def _calc_local_xy(self, x: int, y: int) -> (int, int): + # x_size = self._xrange[1], self._xrange[0] + local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x local_y = ( int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y ) + print("({: >3}, {: >3}) -- ({: >3}, {: >3})".format(x, y, local_x, local_y)) return (local_x, local_y) def update_pointer(self, x: int, y: int) -> None: @@ -473,7 +478,6 @@ def update_pointer(self, x: int, y: int) -> None: rtype: None """ local_x, local_y = self._calc_local_xy(x, y) - if local_x >= 0 or local_y <= 100: if self._update_line: self._draw_pointers(local_x, local_y) diff --git a/examples/displayio_layout_cartesian_dev.py b/examples/displayio_layout_cartesian_dev.py new file mode 100644 index 0000000..072206c --- /dev/null +++ b/examples/displayio_layout_cartesian_dev.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: 2021 Stefan Krüger +# +# SPDX-License-Identifier: MIT +############################# +""" +This is a basic demonstration of a Cartesian widget for line-ploting +""" + +import time +import board +import displayio +from adafruit_displayio_layout.widgets.cartesian import Cartesian + +# create the display on the PyPortal or Clue or PyBadge(for example) +display = board.DISPLAY +# otherwise change this to setup the display +# for display chip driver and pinout you have (e.g. ILI9341) + +# pybadge display: 160x128 +# Create a Cartesian widget +# https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian +my_plane = Cartesian( + x=11, # x position for the plane + y=0, # y plane position + width=140, # display width + height=120, # display height + xrange=(0, 10), # x range + yrange=(0, 10), # y range + major_tick_stroke=1, # ticks width in pixels + major_tick_length=2, # ticks length in pixels + axes_stroke=1, # axes lines width in pixels + axes_color=0x10A0A0, # axes line color + subticks=True, +) + +my_group = displayio.Group() +my_group.append(my_plane) +display.show(my_group) # add high level Group to the display + +data = [ + (0, 0), + (1, 1), + (3, 3), + (5, 5), + (7, 7), + (9, 9), +] + +print("examples/displayio_layout_cartesian_lineplot.py") +for x, y in data: + my_plane.update_line(x, y) + # my_plane.update_pointer(x, y) + time.sleep(2.5) + +while True: + pass diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index ba1fd20..bec782f 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -20,9 +20,9 @@ # Create a Cartesian widget # https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian my_plane = Cartesian( - x=30, # x position for the plane - y=2, # y plane position - width=128, # display width + x=20, # x position for the plane + y=0, # y plane position + width=130, # display width height=105, # display height xrange=(0, 100), # x range yrange=(0, 100), # y range @@ -35,35 +35,18 @@ data = [ (0, 0), (10, 10), - (20, 20), - (30, 30), - (40, 40), + (30, 10), (50, 50), - (60, 60), - (70, 70), - (80, 80), - (90, 90), + (70, 30), + (90, 80), + (95, 80), + (100, 100), ] -# -# data = [ -# (0, 0), -# (10, 10), -# (20, 50), -# (30, 60), -# (40, 40), -# (50, 80), -# (60, 20), -# (70, 60), -# (80, 30), -# (100, 100), -# ] print("examples/displayio_layout_cartesian_lineplot.py") for x, y in data: - # my_plane.update_line(x, y) - my_plane.update_pointer(x, y) - time.sleep(0.5) - print(my_plane.plot_line_point) + my_plane.update_line(x, y) + time.sleep(1) while True: pass From ff529e6c9e83d26174fc8602bc085cfe4f30ae65 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 10:19:10 +0100 Subject: [PATCH 018/132] analyse range checking --- .../widgets/cartesian.py | 89 ++++++++++++++++++- examples/displayio_layout_cartesian_dev.py | 1 + 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index f6dc6ef..334d92a 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -464,11 +464,34 @@ def _calc_local_xy(self, x: int, y: int) -> (int, int): local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x local_y = ( - int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y + int((self._yrange[0] - y) * self._factory) + + (self.height - 1) + + self._nudge_y + ) + print( + "({: >3}, {: >3}) --> ({: >3}, {: >3})".format( + x, + y, + local_x, + local_y, + ) ) - print("({: >3}, {: >3}) -- ({: >3}, {: >3})".format(x, y, local_x, local_y)) return (local_x, local_y) + def _check_local_xy_in_range(self, local_x, local_y): + in_range = False + if (0 <= local_x < self.width) and (0 <= local_y < self.height): + in_range = True + return in_range + + def _check_xy_in_range(self, x, y): + in_range = False + if (self._xrange[0] <= x <= self._xrange[1]) and ( + self._yrange[0] <= y <= self._yrange[1] + ): + in_range = True + return in_range + def update_pointer(self, x: int, y: int) -> None: """updater_pointer function helper function to update pointer in the plane @@ -497,14 +520,44 @@ def update_line(self, x: int, y: int) -> None: :return: None rtype: None """ + print( + "x:{: >4}; _xrange({: >4}, {: >4})\n" + "y:{: >4}; _yrange({: >4}, {: >4})\n" + "".format( + x, + self._xrange[0], + self._xrange[1], + y, + self._yrange[0], + self._yrange[1], + ) + ) local_x, local_y = self._calc_local_xy(x, y) - if x < self._xrange[1] and y < self._yrange[1]: - if local_x > 0 or local_y < 100: + print( + "local_x:{: >4}; _xrange({: >4}, {: >4})\n" + "local_y:{: >4}; _yrange({: >4}, {: >4})\n" + "".format( + local_x, + 0, + self.width, + local_y, + 0, + self.height, + ) + ) + if self._check_xy_in_range(x, y): + if self._check_local_xy_in_range(local_x, local_y): if self._update_line: self._set_plotter_line() self.plot_line_point.append((local_x, local_y)) self._update_line = False else: + print( + "line_start ({: >3}, {: >3})".format( + self.plot_line_point[-1][0], + self.plot_line_point[-1][1], + ) + ) bitmaptools.draw_line( self._screen_bitmap, self.plot_line_point[-1][0], @@ -514,3 +567,31 @@ def update_line(self, x: int, y: int) -> None: 1, ) self.plot_line_point.append((local_x, local_y)) + else: + raise ValueError( + "local_x or local_y out of range:\n" + "local_x:{: >4}; _xrange({: >4}, {: >4})\n" + "local_y:{: >4}; _yrange({: >4}, {: >4})\n" + "".format( + local_x, + 0, + self.width, + local_y, + 0, + self.height, + ) + ) + else: + raise ValueError( + "local_x or local_y out of range:\n" + "x:{: >4}; _xrange({: >4}, {: >4})\n" + "y:{: >4}; _yrange({: >4}, {: >4})\n" + "".format( + x, + self._xrange[0], + self._xrange[1], + y, + self._yrange[0], + self._yrange[1], + ) + ) diff --git a/examples/displayio_layout_cartesian_dev.py b/examples/displayio_layout_cartesian_dev.py index 072206c..49a7c0f 100644 --- a/examples/displayio_layout_cartesian_dev.py +++ b/examples/displayio_layout_cartesian_dev.py @@ -50,6 +50,7 @@ for x, y in data: my_plane.update_line(x, y) # my_plane.update_pointer(x, y) + # print(my_plane.plot_line_point) time.sleep(2.5) while True: From 096cf051645e3e7dd5c46a9921742604ffa22e80 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 11:06:26 +0100 Subject: [PATCH 019/132] fix range checking and add nice errormessages --- .../widgets/cartesian.py | 128 +++++++++++------- examples/displayio_layout_cartesian_dev.py | 17 ++- 2 files changed, 91 insertions(+), 54 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 334d92a..214cf3c 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -468,29 +468,35 @@ def _calc_local_xy(self, x: int, y: int) -> (int, int): + (self.height - 1) + self._nudge_y ) - print( - "({: >3}, {: >3}) --> ({: >3}, {: >3})".format( - x, - y, - local_x, - local_y, - ) - ) + # print( + # "({: >3}, {: >3}) --> ({: >3}, {: >3})".format( + # x, + # y, + # local_x, + # local_y, + # ) + # ) return (local_x, local_y) + def _check_local_x_in_range(self, local_x): + return 0 <= local_x < self.width + + def _check_local_y_in_range(self, local_y): + return 0 <= local_y < self.height + def _check_local_xy_in_range(self, local_x, local_y): - in_range = False - if (0 <= local_x < self.width) and (0 <= local_y < self.height): - in_range = True - return in_range + return self._check_local_x_in_range(local_x) and self._check_local_y_in_range( + local_y + ) + + def _check_x_in_range(self, x): + return self._xrange[0] <= x <= self._xrange[1] + + def _check_y_in_range(self, y): + return self._yrange[0] <= y <= self._yrange[1] def _check_xy_in_range(self, x, y): - in_range = False - if (self._xrange[0] <= x <= self._xrange[1]) and ( - self._yrange[0] <= y <= self._yrange[1] - ): - in_range = True - return in_range + return self._check_x_in_range(x) and self._check_y_in_range(y) def update_pointer(self, x: int, y: int) -> None: """updater_pointer function @@ -520,27 +526,30 @@ def update_line(self, x: int, y: int) -> None: :return: None rtype: None """ + print("") print( - "x:{: >4}; _xrange({: >4}, {: >4})\n" - "y:{: >4}; _yrange({: >4}, {: >4})\n" + "xy: ({: >4}, {: >4}) " + "_xrange: ({: >4}, {: >4}) " + "_yrange: ({: >4}, {: >4}) " "".format( x, + y, self._xrange[0], self._xrange[1], - y, self._yrange[0], self._yrange[1], ) ) local_x, local_y = self._calc_local_xy(x, y) print( - "local_x:{: >4}; _xrange({: >4}, {: >4})\n" - "local_y:{: >4}; _yrange({: >4}, {: >4})\n" + "local_*: ({: >4}, {: >4}) " + " width: ({: >4}, {: >4}) " + " height: ({: >4}, {: >4}) " "".format( local_x, + local_y, 0, self.width, - local_y, 0, self.height, ) @@ -552,12 +561,12 @@ def update_line(self, x: int, y: int) -> None: self.plot_line_point.append((local_x, local_y)) self._update_line = False else: - print( - "line_start ({: >3}, {: >3})".format( - self.plot_line_point[-1][0], - self.plot_line_point[-1][1], - ) - ) + # print( + # "line_start ({: >3}, {: >3})".format( + # self.plot_line_point[-1][0], + # self.plot_line_point[-1][1], + # ) + # ) bitmaptools.draw_line( self._screen_bitmap, self.plot_line_point[-1][0], @@ -568,30 +577,45 @@ def update_line(self, x: int, y: int) -> None: ) self.plot_line_point.append((local_x, local_y)) else: + # for better error messages we check in detail what failed... + if not self._check_local_x_in_range(local_x): + raise ValueError( + "local_x out of range: " + "local_x:{: >4}; _xrange({: >4}, {: >4})" + "".format( + local_x, + 0, + self.width, + ) + ) + if not self._check_local_y_in_range(local_y): + raise ValueError( + "local_y out of range: " + "local_y:{: >4}; _yrange({: >4}, {: >4})" + "".format( + local_y, + 0, + self.height, + ) + ) + else: + if not self._check_x_in_range(x): raise ValueError( - "local_x or local_y out of range:\n" - "local_x:{: >4}; _xrange({: >4}, {: >4})\n" - "local_y:{: >4}; _yrange({: >4}, {: >4})\n" + "x out of range: " + "x:{: >4}; xrange({: >4}, {: >4})" "".format( - local_x, - 0, - self.width, - local_y, - 0, - self.height, + x, + self._xrange[0], + self._xrange[1], ) ) - else: - raise ValueError( - "local_x or local_y out of range:\n" - "x:{: >4}; _xrange({: >4}, {: >4})\n" - "y:{: >4}; _yrange({: >4}, {: >4})\n" - "".format( - x, - self._xrange[0], - self._xrange[1], - y, - self._yrange[0], - self._yrange[1], + if not self._check_y_in_range(y): + raise ValueError( + "y out of range: " + "y:{: >4}; yrange({: >4}, {: >4})" + "".format( + y, + self._yrange[0], + self._yrange[1], + ) ) - ) diff --git a/examples/displayio_layout_cartesian_dev.py b/examples/displayio_layout_cartesian_dev.py index 49a7c0f..a26a5bd 100644 --- a/examples/displayio_layout_cartesian_dev.py +++ b/examples/displayio_layout_cartesian_dev.py @@ -38,20 +38,33 @@ display.show(my_group) # add high level Group to the display data = [ - (0, 0), + # (0, 0), (1, 1), + (1, 15), + (2, 1), + (2, 2), (3, 3), + (4, 3), + (4, 4), (5, 5), + (6, 5), + (6, 6), (7, 7), + (8, 7), + (8, 8), (9, 9), + (10, 9), + (10, 10), ] print("examples/displayio_layout_cartesian_lineplot.py") + +my_plane.update_line(0, 0) for x, y in data: my_plane.update_line(x, y) # my_plane.update_pointer(x, y) # print(my_plane.plot_line_point) - time.sleep(2.5) + time.sleep(0.5) while True: pass From 3bf14f2d1e98bae3a9af71c4936556b28b9e8d27 Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 11:46:19 +0100 Subject: [PATCH 020/132] fix graph alignment error --- .../widgets/cartesian.py | 22 +++++++++++++++++-- examples/displayio_layout_cartesian_dev.py | 4 ++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 214cf3c..ddb5311 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -462,12 +462,26 @@ def _draw_pointers(self, x: int, y: int) -> None: def _calc_local_xy(self, x: int, y: int) -> (int, int): # x_size = self._xrange[1], self._xrange[0] - local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x + # ok we have to calculate the local coordinates from the range: + # we have some things prepared allready: + # self._xrange = xrange + # self._normx = (self._xrange[1] - self._xrange[0]) / 100 + # self._valuex = self.width / 100 + # self._factorx = 100 / (self._xrange[1] - self._xrange[0]) + + local_x = ( + int((x - self._xrange[0]) * self._factorx * self._valuex) + self._nudge_x + ) + # details on `+ (self.height - 1)` + # we make sure we stay in range.. () + # as the bitmap is set to self.width & self.height + # but we are only allowed to draw 0..height-1 and 0..width-1 local_y = ( - int((self._yrange[0] - y) * self._factory) + int((self._yrange[0] - y) * self._factory * self._valuey) + (self.height - 1) + self._nudge_y ) + # print( # "({: >3}, {: >3}) --> ({: >3}, {: >3})".format( # x, @@ -578,6 +592,9 @@ def update_line(self, x: int, y: int) -> None: self.plot_line_point.append((local_x, local_y)) else: # for better error messages we check in detail what failed... + # this should never happen: + # we already checked the range of the input values. + # but in case our calculation is wrong we handle this case to.. if not self._check_local_x_in_range(local_x): raise ValueError( "local_x out of range: " @@ -599,6 +616,7 @@ def update_line(self, x: int, y: int) -> None: ) ) else: + # for better error messages we check in detail what failed... if not self._check_x_in_range(x): raise ValueError( "x out of range: " diff --git a/examples/displayio_layout_cartesian_dev.py b/examples/displayio_layout_cartesian_dev.py index a26a5bd..64ca565 100644 --- a/examples/displayio_layout_cartesian_dev.py +++ b/examples/displayio_layout_cartesian_dev.py @@ -23,7 +23,7 @@ x=11, # x position for the plane y=0, # y plane position width=140, # display width - height=120, # display height + height=110, # display height xrange=(0, 10), # x range yrange=(0, 10), # y range major_tick_stroke=1, # ticks width in pixels @@ -40,7 +40,7 @@ data = [ # (0, 0), (1, 1), - (1, 15), + # (1, 15), # create out of range error (2, 1), (2, 2), (3, 3), From b57349d45d144636340237da156e5c4d49da901c Mon Sep 17 00:00:00 2001 From: s-light Date: Thu, 16 Dec 2021 12:06:21 +0100 Subject: [PATCH 021/132] rearange for less duplicate code. --- .../widgets/cartesian.py | 113 +++++++----------- examples/displayio_layout_cartesian_dev.py | 3 +- 2 files changed, 47 insertions(+), 69 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index ddb5311..1dc948e 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -310,8 +310,6 @@ def __init__( self.append(self._screen_tilegrid) self.append(self._corner_tilegrid) - self._update_line = True - self._pointer = None self._circle_palette = None self.plot_line_point = None @@ -460,36 +458,17 @@ def _draw_pointers(self, x: int, y: int) -> None: self.append(self._pointer) def _calc_local_xy(self, x: int, y: int) -> (int, int): - # x_size = self._xrange[1], self._xrange[0] - - # ok we have to calculate the local coordinates from the range: - # we have some things prepared allready: - # self._xrange = xrange - # self._normx = (self._xrange[1] - self._xrange[0]) / 100 - # self._valuex = self.width / 100 - # self._factorx = 100 / (self._xrange[1] - self._xrange[0]) - local_x = ( int((x - self._xrange[0]) * self._factorx * self._valuex) + self._nudge_x ) - # details on `+ (self.height - 1)` - # we make sure we stay in range.. () - # as the bitmap is set to self.width & self.height - # but we are only allowed to draw 0..height-1 and 0..width-1 + # details on `+ (self.height - 1)` : + # the bitmap is set to self.width & self.height + # but we are only allowed to draw to pixels 0..height-1 and 0..width-1 local_y = ( int((self._yrange[0] - y) * self._factory * self._valuey) + (self.height - 1) + self._nudge_y ) - - # print( - # "({: >3}, {: >3}) --> ({: >3}, {: >3})".format( - # x, - # y, - # local_x, - # local_y, - # ) - # ) return (local_x, local_y) def _check_local_x_in_range(self, local_x): @@ -512,29 +491,9 @@ def _check_y_in_range(self, y): def _check_xy_in_range(self, x, y): return self._check_x_in_range(x) and self._check_y_in_range(y) - def update_pointer(self, x: int, y: int) -> None: - """updater_pointer function - helper function to update pointer in the plane - :param int x: ``x`` coordinate in the local plane - :param int y: ``y`` coordinate in the local plane - :return: None - rtype: None - """ - local_x, local_y = self._calc_local_xy(x, y) - if local_x >= 0 or local_y <= 100: - if self._update_line: - self._draw_pointers(local_x, local_y) - self._update_line = False - else: - self._pointer.x = local_x - self._pointer.y = local_y - - def _set_plotter_line(self) -> None: - self.plot_line_point = [] - - def update_line(self, x: int, y: int) -> None: - """updater_line function - helper function to update pointer in the plane + def _add_point(self, x: int, y: int) -> None: + """_add_point function + helper function to add a point to the graph in the plane :param int x: ``x`` coordinate in the local plane :param int y: ``y`` coordinate in the local plane :return: None @@ -570,26 +529,9 @@ def update_line(self, x: int, y: int) -> None: ) if self._check_xy_in_range(x, y): if self._check_local_xy_in_range(local_x, local_y): - if self._update_line: - self._set_plotter_line() - self.plot_line_point.append((local_x, local_y)) - self._update_line = False - else: - # print( - # "line_start ({: >3}, {: >3})".format( - # self.plot_line_point[-1][0], - # self.plot_line_point[-1][1], - # ) - # ) - bitmaptools.draw_line( - self._screen_bitmap, - self.plot_line_point[-1][0], - self.plot_line_point[-1][1], - local_x, - local_y, - 1, - ) - self.plot_line_point.append((local_x, local_y)) + if self.plot_line_point is None: + self.plot_line_point = [] + self.plot_line_point.append((local_x, local_y)) else: # for better error messages we check in detail what failed... # this should never happen: @@ -637,3 +579,40 @@ def update_line(self, x: int, y: int) -> None: self._yrange[1], ) ) + + def update_pointer(self, x: int, y: int) -> None: + """updater_pointer function + helper function to update pointer in the plane + :param int x: ``x`` coordinate in the local plane + :param int y: ``y`` coordinate in the local plane + :return: None + rtype: None + """ + self._add_point(x, y) + if not self._pointer: + self._draw_pointers( + self.plot_line_point[-1][0], + self.plot_line_point[-1][1], + ) + else: + self._pointer.x = self.plot_line_point[-1][0] + self._pointer.y = self.plot_line_point[-1][1] + + def update_line(self, x: int, y: int) -> None: + """updater_line function + helper function to update line in the plane + :param int x: ``x`` coordinate in the local plane + :param int y: ``y`` coordinate in the local plane + :return: None + rtype: None + """ + self._add_point(x, y) + if len(self.plot_line_point) > 1: + bitmaptools.draw_line( + self._screen_bitmap, + self.plot_line_point[-2][0], + self.plot_line_point[-2][1], + self.plot_line_point[-1][0], + self.plot_line_point[-1][1], + 1, + ) diff --git a/examples/displayio_layout_cartesian_dev.py b/examples/displayio_layout_cartesian_dev.py index 64ca565..39a95c3 100644 --- a/examples/displayio_layout_cartesian_dev.py +++ b/examples/displayio_layout_cartesian_dev.py @@ -62,8 +62,7 @@ my_plane.update_line(0, 0) for x, y in data: my_plane.update_line(x, y) - # my_plane.update_pointer(x, y) - # print(my_plane.plot_line_point) + my_plane.update_pointer(x, y) time.sleep(0.5) while True: From 46d158c045fa8a4f0ed4c9c12d232121ea84efec Mon Sep 17 00:00:00 2001 From: Neradoc Date: Thu, 16 Dec 2021 18:27:06 +0100 Subject: [PATCH 022/132] Adding a bunch of int conversions on cell_anchor_point math In multiple places where `cell["cell_anchor_point"] * X` is used, the int conversion is missing, causing `TypeError: can't convert float to int` when an anchor_point is set to `(0.5, 0.5)` for example. ``` Traceback (most recent call last): File "code.py", line 9, in File "code_pyportal.py", line 285, in switch_page File "/lib/adafruit_displayio_layout/layouts/grid_layout.py", line 413, in add_content File "/lib/adafruit_displayio_layout/layouts/grid_layout.py", line 182, in _layout_cells File "/lib/adafruit_displayio_layout/widgets/widget.py", line 297, in anchored_position File "/lib/adafruit_displayio_layout/widgets/widget.py", line 234, in _update_position TypeError: can't convert float to int ``` I didn't look into the math but I wonder, should it use `round()` rather that `int()` ? (which always rounds down) --- adafruit_displayio_layout/layouts/grid_layout.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 28c7b50..34cd086 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -176,10 +176,10 @@ def _layout_cells(self): cell["content"].anchored_position = ( int(grid_position_x * self._width / grid_size_x) + self.cell_padding - + (cell["cell_anchor_point"][0] * _measured_width), + + int(cell["cell_anchor_point"][0] * _measured_width), int(grid_position_y * self._height / grid_size_y) + self.cell_padding - + (cell["cell_anchor_point"][1] * _measured_height), + + int(cell["cell_anchor_point"][1] * _measured_height), ) self.append(cell["content"]) @@ -236,29 +236,29 @@ def _layout_cells(self): cell["content"].anchored_position[1] + _measured_height + self.cell_padding - - (cell["cell_anchor_point"][1] * _measured_height) + - int(cell["cell_anchor_point"][1] * _measured_height) ) - 1 _bottom_line_loc_x = ( cell["content"].anchored_position[0] - self.cell_padding - - (cell["cell_anchor_point"][0] * _measured_width) + - int(cell["cell_anchor_point"][0] * _measured_width) ) _top_line_loc_y = ( cell["content"].anchored_position[1] - self.cell_padding - - (cell["cell_anchor_point"][1] * _measured_height) + - int(cell["cell_anchor_point"][1] * _measured_height) ) _top_line_loc_x = ( cell["content"].anchored_position[0] - self.cell_padding - - (cell["cell_anchor_point"][0] * _measured_width) + - int(cell["cell_anchor_point"][0] * _measured_width) ) _right_line_loc_y = ( cell["content"].anchored_position[1] - self.cell_padding - - (cell["cell_anchor_point"][1] * _measured_height) + - int(cell["cell_anchor_point"][1] * _measured_height) ) _right_line_loc_x = ( ( @@ -267,7 +267,7 @@ def _layout_cells(self): + self.cell_padding ) - 1 - - (cell["cell_anchor_point"][0] * _measured_width) + - int(cell["cell_anchor_point"][0] * _measured_width) ) _horizontal_divider_line = displayio.Shape( From 207b58312cdeef015c3ea50433ca31a85d9944a1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 16 Dec 2021 17:56:46 -0600 Subject: [PATCH 023/132] handle float locations --- adafruit_displayio_layout/widgets/widget.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index d1cd226..5efbf93 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -228,12 +228,12 @@ def _update_position(self): """ if (self._anchor_point is not None) and (self._anchored_position is not None): - self.x = ( + self.x = int( self._anchored_position[0] - int(self._anchor_point[0] * self._bounding_box[2]) - self._bounding_box[0] ) - self.y = ( + self.y = int( self._anchored_position[1] - int(self._anchor_point[1] * self._bounding_box[3]) - self._bounding_box[1] From c356d2aff5cc153588f65bd1d879a0d8a9a09c9f Mon Sep 17 00:00:00 2001 From: s-light Date: Fri, 17 Dec 2021 06:46:09 +0100 Subject: [PATCH 024/132] add verbose flag for debug output --- .../widgets/cartesian.py | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 1dc948e..b59e416 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -74,6 +74,7 @@ class Cartesian(Widget): :param int nudge_y: movement in pixels in the y direction to move the origin. Defaults to 0 + :param bool verbose: print debugging information in some internal functions. Default to False **Quickstart: Importing and using Cartesian** @@ -181,11 +182,14 @@ def __init__( subticks: bool = False, nudge_x: int = 0, nudge_y: int = 0, + verbose: bool = False, **kwargs, ) -> None: super().__init__(**kwargs) + self._verbose = verbose + self._background_color = background_color self._axes_line_color = axes_color @@ -499,34 +503,35 @@ def _add_point(self, x: int, y: int) -> None: :return: None rtype: None """ - print("") - print( - "xy: ({: >4}, {: >4}) " - "_xrange: ({: >4}, {: >4}) " - "_yrange: ({: >4}, {: >4}) " - "".format( - x, - y, - self._xrange[0], - self._xrange[1], - self._yrange[0], - self._yrange[1], - ) - ) local_x, local_y = self._calc_local_xy(x, y) - print( - "local_*: ({: >4}, {: >4}) " - " width: ({: >4}, {: >4}) " - " height: ({: >4}, {: >4}) " - "".format( - local_x, - local_y, - 0, - self.width, - 0, - self.height, + if self._verbose: + print("") + print( + "xy: ({: >4}, {: >4}) " + "_xrange: ({: >4}, {: >4}) " + "_yrange: ({: >4}, {: >4}) " + "".format( + x, + y, + self._xrange[0], + self._xrange[1], + self._yrange[0], + self._yrange[1], + ) + ) + print( + "local_*: ({: >4}, {: >4}) " + " width: ({: >4}, {: >4}) " + " height: ({: >4}, {: >4}) " + "".format( + local_x, + local_y, + 0, + self.width, + 0, + self.height, + ) ) - ) if self._check_xy_in_range(x, y): if self._check_local_xy_in_range(local_x, local_y): if self.plot_line_point is None: From 9661bce9fc21d56a49d3e754629b1915111dc8c4 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 19 Dec 2021 12:02:25 +0100 Subject: [PATCH 025/132] rename _screen_bitmap to _plot_bitmap, add clear_plot() --- .../widgets/cartesian.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index b59e416..ab91f1b 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -254,8 +254,8 @@ def __init__( self._axesy_bitmap = displayio.Bitmap(self._axesy_width, self.height, 4) self._axesy_bitmap.fill(0) - self._screen_bitmap = displayio.Bitmap(self.width, self.height, 5) - self._screen_bitmap.fill(5) + self._plot_bitmap = displayio.Bitmap(self.width, self.height, 5) + self.clear_plot() self._screen_palette = displayio.Palette(6) self._screen_palette.make_transparent(0) self._screen_palette[1] = self._tick_color @@ -297,7 +297,7 @@ def __init__( ) self._screen_tilegrid = displayio.TileGrid( - self._screen_bitmap, + self._plot_bitmap, pixel_shader=self._screen_palette, x=0, y=0, @@ -614,10 +614,21 @@ def update_line(self, x: int, y: int) -> None: self._add_point(x, y) if len(self.plot_line_point) > 1: bitmaptools.draw_line( - self._screen_bitmap, + self._plot_bitmap, self.plot_line_point[-2][0], self.plot_line_point[-2][1], self.plot_line_point[-1][0], self.plot_line_point[-1][1], 1, ) + + def clear_plot(self, palette_index=5): + """clear_plot function. + + clear plotted lines + :param int palette_index: color palett index. Defaults to 5 + :return: None + rtype: None + """ + self.plot_line_point = None + self._plot_bitmap.fill(palette_index) From 779fc7a1e48588980531fff9de6378d1413520f9 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 19 Dec 2021 19:42:42 +0100 Subject: [PATCH 026/132] cleanup example --- examples/displayio_layout_cartesian_dev.py | 69 ------------------- .../displayio_layout_cartesian_lineplot.py | 37 ++++++---- 2 files changed, 24 insertions(+), 82 deletions(-) delete mode 100644 examples/displayio_layout_cartesian_dev.py diff --git a/examples/displayio_layout_cartesian_dev.py b/examples/displayio_layout_cartesian_dev.py deleted file mode 100644 index 39a95c3..0000000 --- a/examples/displayio_layout_cartesian_dev.py +++ /dev/null @@ -1,69 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Stefan Krüger -# -# SPDX-License-Identifier: MIT -############################# -""" -This is a basic demonstration of a Cartesian widget for line-ploting -""" - -import time -import board -import displayio -from adafruit_displayio_layout.widgets.cartesian import Cartesian - -# create the display on the PyPortal or Clue or PyBadge(for example) -display = board.DISPLAY -# otherwise change this to setup the display -# for display chip driver and pinout you have (e.g. ILI9341) - -# pybadge display: 160x128 -# Create a Cartesian widget -# https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian -my_plane = Cartesian( - x=11, # x position for the plane - y=0, # y plane position - width=140, # display width - height=110, # display height - xrange=(0, 10), # x range - yrange=(0, 10), # y range - major_tick_stroke=1, # ticks width in pixels - major_tick_length=2, # ticks length in pixels - axes_stroke=1, # axes lines width in pixels - axes_color=0x10A0A0, # axes line color - subticks=True, -) - -my_group = displayio.Group() -my_group.append(my_plane) -display.show(my_group) # add high level Group to the display - -data = [ - # (0, 0), - (1, 1), - # (1, 15), # create out of range error - (2, 1), - (2, 2), - (3, 3), - (4, 3), - (4, 4), - (5, 5), - (6, 5), - (6, 6), - (7, 7), - (8, 7), - (8, 8), - (9, 9), - (10, 9), - (10, 10), -] - -print("examples/displayio_layout_cartesian_lineplot.py") - -my_plane.update_line(0, 0) -for x, y in data: - my_plane.update_line(x, y) - my_plane.update_pointer(x, y) - time.sleep(0.5) - -while True: - pass diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index bec782f..3d396bb 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -20,12 +20,12 @@ # Create a Cartesian widget # https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian my_plane = Cartesian( - x=20, # x position for the plane - y=0, # y plane position - width=130, # display width + x=15, # x position for the plane + y=2, # y plane position + width=140, # display width height=105, # display height - xrange=(0, 100), # x range - yrange=(0, 100), # y range + xrange=(0, 10), # x range + yrange=(0, 10), # y range ) my_group = displayio.Group() @@ -33,20 +33,31 @@ display.show(my_group) # add high level Group to the display data = [ - (0, 0), + # (0, 0), # we do this point manually - so we have no wait... + (1, 1), + (2, 1), + (2, 2), + (3, 3), + (4, 3), + (4, 4), + (5, 5), + (6, 5), + (6, 6), + (7, 7), + (8, 7), + (8, 8), + (9, 9), + (10, 9), (10, 10), - (30, 10), - (50, 50), - (70, 30), - (90, 80), - (95, 80), - (100, 100), ] print("examples/displayio_layout_cartesian_lineplot.py") + +# first point without a wait. +my_plane.update_line(0, 0) for x, y in data: my_plane.update_line(x, y) - time.sleep(1) + time.sleep(0.5) while True: pass From caa160fc846fd419bd480680779224be5b5ed607 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 19 Dec 2021 20:06:18 +0100 Subject: [PATCH 027/132] rename `update_line` to `add_line` --- adafruit_displayio_layout/widgets/cartesian.py | 13 +++++++++---- examples/displayio_layout_cartesian_lineplot.py | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index ab91f1b..1cd29e7 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -603,9 +603,12 @@ def update_pointer(self, x: int, y: int) -> None: self._pointer.x = self.plot_line_point[-1][0] self._pointer.y = self.plot_line_point[-1][1] - def update_line(self, x: int, y: int) -> None: - """updater_line function - helper function to update line in the plane + def add_line(self, x: int, y: int) -> None: + """add_line function. + + add line to the plane. + multiple calls create a line-plot graph. + :param int x: ``x`` coordinate in the local plane :param int y: ``y`` coordinate in the local plane :return: None @@ -625,7 +628,9 @@ def update_line(self, x: int, y: int) -> None: def clear_plot(self, palette_index=5): """clear_plot function. - clear plotted lines + clear all added lines + (clear line-plot graph) + :param int palette_index: color palett index. Defaults to 5 :return: None rtype: None diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index 3d396bb..63ca8e5 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -56,7 +56,7 @@ # first point without a wait. my_plane.update_line(0, 0) for x, y in data: - my_plane.update_line(x, y) + my_plane.add_line(x, y) time.sleep(0.5) while True: From 38b53df2ffe18edd6994293c9412e4b984b128c3 Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 19 Dec 2021 20:08:26 +0100 Subject: [PATCH 028/132] renamed `clear_plot` to `clear_lines` for better name matching --- adafruit_displayio_layout/widgets/cartesian.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 1cd29e7..888c1e0 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -625,8 +625,8 @@ def add_line(self, x: int, y: int) -> None: 1, ) - def clear_plot(self, palette_index=5): - """clear_plot function. + def clear_lines(self, palette_index=5): + """clear_lines function. clear all added lines (clear line-plot graph) From 529cbea8e0d580d0121d904b9f91a9d75481bc0a Mon Sep 17 00:00:00 2001 From: s-light Date: Sun, 19 Dec 2021 22:44:01 +0100 Subject: [PATCH 029/132] fix doc strings --- adafruit_displayio_layout/widgets/cartesian.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 888c1e0..55392d9 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -612,6 +612,7 @@ def add_line(self, x: int, y: int) -> None: :param int x: ``x`` coordinate in the local plane :param int y: ``y`` coordinate in the local plane :return: None + rtype: None """ self._add_point(x, y) @@ -633,6 +634,7 @@ def clear_lines(self, palette_index=5): :param int palette_index: color palett index. Defaults to 5 :return: None + rtype: None """ self.plot_line_point = None From f1bf72a4a0385a002691bd8f33302a5ac7dd62cc Mon Sep 17 00:00:00 2001 From: s-light Date: Mon, 20 Dec 2021 19:18:34 +0100 Subject: [PATCH 030/132] fix missed rename.. --- adafruit_displayio_layout/widgets/cartesian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 55392d9..6867541 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -255,7 +255,7 @@ def __init__( self._axesy_bitmap.fill(0) self._plot_bitmap = displayio.Bitmap(self.width, self.height, 5) - self.clear_plot() + self.clear_lines() self._screen_palette = displayio.Palette(6) self._screen_palette.make_transparent(0) self._screen_palette[1] = self._tick_color From 1f4ed4a405642c8f5300e6a904fe5862153ff9e3 Mon Sep 17 00:00:00 2001 From: s-light Date: Tue, 21 Dec 2021 16:16:17 +0100 Subject: [PATCH 031/132] fix name --- examples/displayio_layout_cartesian_lineplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index 63ca8e5..e98f4d0 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -54,7 +54,7 @@ print("examples/displayio_layout_cartesian_lineplot.py") # first point without a wait. -my_plane.update_line(0, 0) +my_plane.add_line(0, 0) for x, y in data: my_plane.add_line(x, y) time.sleep(0.5) From 8d8c94d4a6f15e74261e5a79c1717e75119614a7 Mon Sep 17 00:00:00 2001 From: s-light Date: Wed, 22 Dec 2021 04:57:14 +0100 Subject: [PATCH 032/132] change names: `*_line` to `*_plot_line` --- adafruit_displayio_layout/widgets/cartesian.py | 10 +++++----- examples/displayio_layout_cartesian_lineplot.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 6867541..8a0d147 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -255,7 +255,7 @@ def __init__( self._axesy_bitmap.fill(0) self._plot_bitmap = displayio.Bitmap(self.width, self.height, 5) - self.clear_lines() + self.clear_plot_lines() self._screen_palette = displayio.Palette(6) self._screen_palette.make_transparent(0) self._screen_palette[1] = self._tick_color @@ -603,8 +603,8 @@ def update_pointer(self, x: int, y: int) -> None: self._pointer.x = self.plot_line_point[-1][0] self._pointer.y = self.plot_line_point[-1][1] - def add_line(self, x: int, y: int) -> None: - """add_line function. + def add_plot_line(self, x: int, y: int) -> None: + """add_plot_line function. add line to the plane. multiple calls create a line-plot graph. @@ -626,8 +626,8 @@ def add_line(self, x: int, y: int) -> None: 1, ) - def clear_lines(self, palette_index=5): - """clear_lines function. + def clear_plot_lines(self, palette_index=5): + """clear_plot_lines function. clear all added lines (clear line-plot graph) diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index e98f4d0..5725f39 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -54,9 +54,9 @@ print("examples/displayio_layout_cartesian_lineplot.py") # first point without a wait. -my_plane.add_line(0, 0) +my_plane.add_plot_line(0, 0) for x, y in data: - my_plane.add_line(x, y) + my_plane.add_plot_line(x, y) time.sleep(0.5) while True: From aa7ed979635476277445b26fb26d793d5f7482de Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 3 Jan 2022 11:25:59 -0600 Subject: [PATCH 033/132] transparency in icon image. Background color for label. --- .../widgets/icon_widget.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/widgets/icon_widget.py b/adafruit_displayio_layout/widgets/icon_widget.py index f2fe0fd..b09ea66 100644 --- a/adafruit_displayio_layout/widgets/icon_widget.py +++ b/adafruit_displayio_layout/widgets/icon_widget.py @@ -41,7 +41,10 @@ class IconWidget(Widget, Control): :param string icon: the filepath of the bmp image to be used as the icon. :param boolean on_disk: if True use OnDiskBitmap instead of imageload. This can be helpful to save memory. Defaults to False - + :param Optional[int] transparent_index: if not None this color index will get set to + transparent on the palette of the icon. + :param Optional[int] label_background: if not None this color will be used as a background + for the icon label. :param int x: x location the icon widget should be placed. Pixel coordinates. :param int y: y location the icon widget should be placed. Pixel coordinates. :param anchor_point: (X,Y) values from 0.0 to 1.0 to define the anchor point relative to the @@ -51,16 +54,30 @@ class IconWidget(Widget, Control): :type anchored_position: Tuple[int, int] """ - def __init__(self, label_text, icon, on_disk=False, **kwargs): + # pylint: disable=too-many-arguments + + def __init__( + self, + label_text, + icon, + on_disk=False, + transparent_index=None, + label_background=None, + **kwargs + ): super().__init__(**kwargs) self._icon = icon if on_disk: image = OnDiskBitmap(self._icon) + if transparent_index is not None: + image.pixel_shader.make_transparent(transparent_index) tile_grid = TileGrid(image, pixel_shader=image.pixel_shader) else: image, palette = adafruit_imageload.load(icon) + if transparent_index is not None: + palette.make_transparent(transparent_index) tile_grid = TileGrid(image, pixel_shader=palette) self.append(tile_grid) _label = bitmap_label.Label( @@ -70,6 +87,10 @@ def __init__(self, label_text, icon, on_disk=False, **kwargs): anchor_point=(0.5, 0), anchored_position=(image.width // 2, image.height), ) + + if label_background is not None: + _label.background_color = label_background + self.append(_label) self.touch_boundary = ( 0, From 6e3862ddf3af0c40c27b06c008d4df72329b11b9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 3 Jan 2022 11:40:03 -0600 Subject: [PATCH 034/132] add bitmap_font to requirements. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index bdd5ac6..b0b270d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ adafruit-blinka-displayio adafruit-circuitpython-display-shapes adafruit-circuitpython-imageload adafruit-circuitpython-display-text +adafruit-circuitpython-bitmap-font From 1440a0ec690105eaa3d88ee27fcb8883392e0518 Mon Sep 17 00:00:00 2001 From: dherrada Date: Thu, 13 Jan 2022 16:27:30 -0500 Subject: [PATCH 035/132] First part of patch Signed-off-by: dherrada --- .../PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md | 2 +- .github/workflows/build.yml | 6 +++--- .github/workflows/release.yml | 8 ++++---- .readthedocs.yaml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md b/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md index 71ef8f8..8de294e 100644 --- a/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md +++ b/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md @@ -4,7 +4,7 @@ Thank you for contributing! Before you submit a pull request, please read the following. -Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://circuitpython.readthedocs.io/en/latest/docs/design_guide.html +Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aea7267..84c964d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,10 +22,10 @@ jobs: awk -F '\/' '{ print tolower($2) }' | tr '_' '-' ) - - name: Set up Python 3.7 - uses: actions/setup-python@v1 + - name: Set up Python 3.x + uses: actions/setup-python@v2 with: - python-version: 3.7 + python-version: "3.x" - name: Versions run: | python3 --version diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d0015a..a65e5de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,10 +24,10 @@ jobs: awk -F '\/' '{ print tolower($2) }' | tr '_' '-' ) - - name: Set up Python 3.6 - uses: actions/setup-python@v1 + - name: Set up Python 3.x + uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: "3.x" - name: Versions run: | python3 --version @@ -67,7 +67,7 @@ jobs: echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) - name: Set up Python if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1335112..f8b2891 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -9,7 +9,7 @@ version: 2 python: - version: "3.7" + version: "3.x" install: - requirements: docs/requirements.txt - requirements: requirements.txt From d39dd85e7ad04ed0daede935bcaa72f1010e268e Mon Sep 17 00:00:00 2001 From: dherrada Date: Mon, 24 Jan 2022 16:46:16 -0500 Subject: [PATCH 036/132] Updated docs link, updated python docs link, updated setup.py --- README.rst | 4 ++-- docs/conf.py | 4 ++-- docs/index.rst | 2 +- setup.py | 2 -- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 68a3b76..41bad28 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Introduction ============ .. image:: https://readthedocs.org/projects/adafruit-circuitpython-displayio-layout/badge/?version=latest - :target: https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/ + :target: https://docs.circuitpython.org/projects/displayio-layout/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/discord/327254708534116352.svg @@ -63,7 +63,7 @@ See scripts in the examples directory of this repository. Documentation ============= -API documentation for this library can be found on `Read the Docs `_. +API documentation for this library can be found on `Read the Docs `_. Contributing ============ diff --git a/docs/conf.py b/docs/conf.py index 516748e..6cfd605 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,8 +35,8 @@ intersphinx_mapping = { - "python": ("https://docs.python.org/3.4", None), - "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), + "python": ("https://docs.python.org/3", None), + "CircuitPython": ("https://docs.circuitpython.org/en/latest/", None), } # Add any paths that contain templates here, relative to this directory. diff --git a/docs/index.rst b/docs/index.rst index 5908e6f..f57da77 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -34,7 +34,7 @@ Table of Contents :caption: Other Links Download - CircuitPython Reference Documentation + CircuitPython Reference Documentation CircuitPython Support Forum Discord Chat Adafruit Learning System diff --git a/setup.py b/setup.py index f17d31d..564522f 100644 --- a/setup.py +++ b/setup.py @@ -51,8 +51,6 @@ "Topic :: System :: Hardware", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", ], # What does your project relate to? keywords="adafruit blinka circuitpython micropython displayio_layout displayio gui layout " From 78b505756e2cccbe094e3ec9cd57ec5b792dc6c5 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Thu, 10 Feb 2022 09:56:01 -0500 Subject: [PATCH 037/132] Consolidate Documentation sections of README --- README.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 41bad28..6403d92 100644 --- a/README.rst +++ b/README.rst @@ -65,14 +65,11 @@ Documentation API documentation for this library can be found on `Read the Docs `_. +For information on building library documentation, please check out `this guide `_. + Contributing ============ Contributions are welcome! Please read our `Code of Conduct `_ before contributing to help this project stay welcoming. - -Documentation -============= - -For information on building library documentation, please check out `this guide `_. From 80c691c4a9df06d0be4e9e259c88d38f3fa94376 Mon Sep 17 00:00:00 2001 From: dherrada Date: Mon, 14 Feb 2022 15:35:02 -0500 Subject: [PATCH 038/132] Fixed readthedocs build Signed-off-by: dherrada --- .readthedocs.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f8b2891..33c2a61 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,8 +8,12 @@ # Required version: 2 +build: + os: ubuntu-20.04 + tools: + python: "3" + python: - version: "3.x" install: - requirements: docs/requirements.txt - requirements: requirements.txt From 094d24973b160b595dbdb8793ad2f0862c595ae9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 26 Mar 2022 15:08:46 -0500 Subject: [PATCH 039/132] adding page_layout and examples --- .../layouts/page_layout.py | 218 ++++++++++++++++++ ...splayio_layout_page_layout_advancedtest.py | 102 ++++++++ ...displayio_layout_page_layout_simpletest.py | 60 +++++ 3 files changed, 380 insertions(+) create mode 100644 adafruit_displayio_layout/layouts/page_layout.py create mode 100644 examples/displayio_layout_page_layout_advancedtest.py create mode 100644 examples/displayio_layout_page_layout_simpletest.py diff --git a/adafruit_displayio_layout/layouts/page_layout.py b/adafruit_displayio_layout/layouts/page_layout.py new file mode 100644 index 0000000..4cab143 --- /dev/null +++ b/adafruit_displayio_layout/layouts/page_layout.py @@ -0,0 +1,218 @@ +# SPDX-FileCopyrightText: 2022 Tim Cocks +# +# SPDX-License-Identifier: MIT + +""" +`page_layout` +================================================================================ + +A layout that organizes pages which can be viewed one at a time. + + +* Author(s): Tim Cocks + +Implementation Notes +-------------------- + +**Hardware:** + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://github.com/adafruit/circuitpython/releases + +""" +try: + # Used only for typing + # pylint: disable=unused-import + from typing import Tuple + +except ImportError: + pass + +import displayio + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + + +class PageLayout(displayio.Group): + """ + A layout that organizes children into a grid table structure. + + :param int x: x location the layout should be placed. Pixel coordinates. + :param int y: y location the layout should be placed. Pixel coordinates. + """ + + def __init__( + self, + x, + y, + ): + super().__init__(x=x, y=y) + self.x = x + self.y = y + + self._page_content_list = [] + self._cur_showing_index = 0 + + def add_content(self, page_content, page_name=None): + """Add a child to the grid. + + :param page_content: the content for the page typically a Group + :param page_name: the name of this page + + :return: None""" + + _page_group = displayio.Group() + _page_group.append(page_content) + + sub_view_obj = { + "content": _page_group, + "page_name": page_name, + } + + if len(self._page_content_list) > 0: + _page_group.hidden = True + + self._page_content_list.append(sub_view_obj) + self.append(_page_group) + + def _check_args(self, page_name, page_index): + """ + Ensure supplied arguments are valid + + :param string page_name: name of a page + :param int page_index: index of a page + :return: None + """ + if page_name is None and page_index is None: + raise AttributeError("Must pass either page_name or page_index") + + if page_index is not None and page_name is not None: + raise AttributeError( + "Must pass either page_name or page_index only one or the other" + ) + + if page_index is not None: + if page_index >= len(self._page_content_list): + raise KeyError( + "KeyError at index {} in list length {}".format( + page_index, len(self._page_content_list) + ), + ) + + if page_name is not None: + _found = False + for page in self._page_content_list: + if not _found: + if page_name == page["page_name"]: + _found = True + + if not _found: + raise KeyError("Page with name {} not found".format(page_name)) + + def get_page(self, page_name=None, page_index=None): + """ + Return a page content based on the name or index. Raises + KeyError if the page was not found in the PageLayout. + + :param string page_name: the name of the page to lookup + :param int page_index: the index of the page to lookup + :return: the displayio content object at those coordinates + """ + + self._check_args(page_name, page_index) + + if page_index: + return self._page_content_list[page_index] + + if page_name: + for cell in self._page_content_list: + if cell["page_name"] == page_name: + return cell + + raise KeyError( + "PageLayout does not contain page: {}".format( + page_index if page_index else page_name + ) + ) + + def show_page(self, page_name=None, page_index=None): + """ + Show the specified page, and hide all other pages. + + :param string page_name: The name of a page to show + :param int page_index: The index of a page to show + :return: None + """ + + self._check_args(page_name, page_index) + + for cur_index, page in enumerate(self._page_content_list): + if page_name is not None: + if page["page_name"] == page_name: + self._cur_showing_index = cur_index + page["content"].hidden = False + else: + page["content"].hidden = True + + if page_index is not None: + if cur_index == page_index: + self._cur_showing_index = cur_index + page["content"].hidden = False + else: + page["content"].hidden = True + + @property + def showing_page_index(self): + """ + Index of the currently showing page + :return int: showing_page_index + """ + return self._cur_showing_index + + @showing_page_index.setter + def showing_page_index(self, new_index): + self.show_page(page_index=new_index) + + @property + def showing_page_name(self): + """ + Name of the currently showing page + :return string: showing_page_name + """ + return self._page_content_list[self._cur_showing_index]["page_name"] + + @showing_page_name.setter + def showing_page_name(self, new_name): + self.show_page(page_name=new_name) + + def next_page(self, loop=True): + """ + Hide the current page and show the next one in the list by index + :param bool loop: whether to loop from the last page back to the first + :return: None + """ + + if self._cur_showing_index + 1 < len(self._page_content_list): + self.show_page(page_index=self._cur_showing_index + 1) + else: + if not loop: + print("No more pages") + else: + self.show_page(page_index=0) + + def previous_page(self, loop=True): + """ + Hide the current page and show the previous one in the list by index + :param bool loop: whether to loop from the first page to the last one + :return: None + """ + if self._cur_showing_index - 1 >= 0: + self.show_page(page_index=self._cur_showing_index - 1) + else: + if not loop: + print("No more pages") + else: + self.show_page(page_index=len(self._page_content_list) - 1) diff --git a/examples/displayio_layout_page_layout_advancedtest.py b/examples/displayio_layout_page_layout_advancedtest.py new file mode 100644 index 0000000..a239d10 --- /dev/null +++ b/examples/displayio_layout_page_layout_advancedtest.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2022 Tim C +# +# SPDX-License-Identifier: MIT +""" +Make a PageLayout and illustrate all of it's features +""" +import time +import displayio +import board +import terminalio +from adafruit_display_text.bitmap_label import Label +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.triangle import Triangle +from adafruit_displayio_layout.layouts.page_layout import PageLayout + +# built-in display +display = board.DISPLAY + +# create and show main_group +main_group = displayio.Group() +display.show(main_group) + +# create the page layout +test_page_layout = PageLayout(x=0, y=0) + +# make 3 pages of content +page_1_group = displayio.Group() +page_2_group = displayio.Group() +page_3_group = displayio.Group() + +# labels +page_1_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This is the first page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_2_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This page is the second page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_3_lbl = Label( + font=terminalio.FONT, + scale=2, + text="The third page is fun!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) + +# shapes +square = Rect(x=20, y=70, width=40, height=40, fill=0x00DD00) +circle = Circle(50, 100, r=30, fill=0xDD00DD) +triangle = Triangle(50, 0, 100, 50, 0, 50, fill=0xDDDD00) +triangle.x = 80 +triangle.y = 70 + +# add everything to their page groups +page_1_group.append(square) +page_1_group.append(page_1_lbl) +page_2_group.append(page_2_lbl) +page_2_group.append(circle) +page_3_group.append(page_3_lbl) +page_3_group.append(triangle) + +# add the pages to the layout, supply your own page names +test_page_layout.add_content(page_1_group, "page_1") +test_page_layout.add_content(page_2_group, "page_2") +test_page_layout.add_content(page_3_group, "page_3") + +# add it to the group that is showing on the display +main_group.append(test_page_layout) + +# change page with function by name +test_page_layout.show_page(page_name="page_3") +print("showing page index:{}".format(test_page_layout.showing_page_index)) +time.sleep(1) + +# change page with function by index +test_page_layout.show_page(page_index=0) +print("showing page name: {}".format(test_page_layout.showing_page_name)) +time.sleep(1) + +# change page by updating the page name property +test_page_layout.showing_page_name = "page_3" +print("showing page index: {}".format(test_page_layout.showing_page_index)) +time.sleep(1) + +# change page by updating the page index property +test_page_layout.showing_page_index = 1 +print("showing page name: {}".format(test_page_layout.showing_page_name)) +time.sleep(5) + +print("starting loop") +while True: + time.sleep(1) + # change page by next page function. It will loop by default + test_page_layout.next_page() diff --git a/examples/displayio_layout_page_layout_simpletest.py b/examples/displayio_layout_page_layout_simpletest.py new file mode 100644 index 0000000..28dd2b5 --- /dev/null +++ b/examples/displayio_layout_page_layout_simpletest.py @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: 2022 Tim C +# +# SPDX-License-Identifier: MIT +""" +Make a PageLayout with two pages and change between them. +""" +import time +import displayio +import board +import terminalio +from adafruit_display_text.bitmap_label import Label +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_displayio_layout.layouts.page_layout import PageLayout + +# built-in display +display = board.DISPLAY + +# create and show main_group +main_group = displayio.Group() +display.show(main_group) + +# create the page layout +test_page_layout = PageLayout(x=0, y=0) + +page_1_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This is the first page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_2_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This page is the second page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) + +page_1_group = displayio.Group() +page_2_group = displayio.Group() + +square = Rect(x=20, y=70, width=40, height=40, fill=0x00DD00) +circle = Circle(50, 100, r=30, fill=0xDD00DD) + +page_1_group.append(square) +page_1_group.append(page_1_lbl) + +page_2_group.append(page_2_lbl) +page_2_group.append(circle) + +test_page_layout.add_content(page_1_group, "page_1") +test_page_layout.add_content(page_2_group, "page_2") + +main_group.append(test_page_layout) +while True: + + time.sleep(1) + test_page_layout.next_page() From d16c8779c887a746e7e7bd44c2c33625386589ba Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 28 Mar 2022 12:25:38 -0500 Subject: [PATCH 040/132] fix checks for None --- adafruit_displayio_layout/layouts/page_layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/layouts/page_layout.py b/adafruit_displayio_layout/layouts/page_layout.py index 4cab143..e395937 100644 --- a/adafruit_displayio_layout/layouts/page_layout.py +++ b/adafruit_displayio_layout/layouts/page_layout.py @@ -124,10 +124,10 @@ def get_page(self, page_name=None, page_index=None): self._check_args(page_name, page_index) - if page_index: + if page_index is not None: return self._page_content_list[page_index] - if page_name: + if page_name is not None: for cell in self._page_content_list: if cell["page_name"] == page_name: return cell From 50a46d3956016672002eecc4a55193d86a3d49de Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 28 Mar 2022 12:37:28 -0500 Subject: [PATCH 041/132] add showing_page_content property getter. --- adafruit_displayio_layout/layouts/page_layout.py | 8 ++++++++ examples/displayio_layout_page_layout_advancedtest.py | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/adafruit_displayio_layout/layouts/page_layout.py b/adafruit_displayio_layout/layouts/page_layout.py index e395937..bee92ba 100644 --- a/adafruit_displayio_layout/layouts/page_layout.py +++ b/adafruit_displayio_layout/layouts/page_layout.py @@ -188,6 +188,14 @@ def showing_page_name(self): def showing_page_name(self, new_name): self.show_page(page_name=new_name) + @property + def showing_page_content(self): + """ + The content object for the currently showing page + :return Displayable: showing_page_content + """ + return self._page_content_list[self._cur_showing_index]["content"][0] + def next_page(self, loop=True): """ Hide the current page and show the next one in the list by index diff --git a/examples/displayio_layout_page_layout_advancedtest.py b/examples/displayio_layout_page_layout_advancedtest.py index a239d10..fa5a4ca 100644 --- a/examples/displayio_layout_page_layout_advancedtest.py +++ b/examples/displayio_layout_page_layout_advancedtest.py @@ -95,6 +95,16 @@ print("showing page name: {}".format(test_page_layout.showing_page_name)) time.sleep(5) +another_text = Label( + terminalio.FONT, + text="And another thing!", + scale=2, + color=0x00FF00, + anchor_point=(0, 0), + anchored_position=(100, 100), +) +test_page_layout.showing_page_content.append(another_text) + print("starting loop") while True: time.sleep(1) From cbfcca0ca28ebbdfb799ef3adac33dd1233a27eb Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Mon, 28 Mar 2022 15:52:04 -0400 Subject: [PATCH 042/132] Update Black to latest. Signed-off-by: Kattni Rembor --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43d1385..29230db 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: - repo: https://github.com/python/black - rev: 20.8b1 + rev: 22.3.0 hooks: - id: black - repo: https://github.com/fsfe/reuse-tool From 0db65db7cc4c97c75c1ea0ac9c88513da59a2777 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Thu, 21 Apr 2022 15:45:16 -0400 Subject: [PATCH 043/132] Updated gitignore Signed-off-by: evaherrada --- .gitignore | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 2c6ddfd..544ec4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,47 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries # -# SPDX-License-Identifier: Unlicense +# SPDX-License-Identifier: MIT +# Do not include files and directories created by your personal work environment, such as the IDE +# you use, except for those already listed here. Pull requests including changes to this file will +# not be accepted. + +# This .gitignore file contains rules for files generated by working with CircuitPython libraries, +# including building Sphinx, testing with pip, and creating a virual environment, as well as the +# MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs. + +# If you find that there are files being generated on your machine that should not be included in +# your git commit, you should create a .gitignore_global file on your computer to include the +# files created by your personal setup. To do so, follow the two steps below. + +# First, create a file called .gitignore_global somewhere convenient for you, and add rules for +# the files you want to exclude from git commits. + +# Second, configure Git to use the exclude file for all Git repositories by running the +# following via commandline, replacing "path/to/your/" with the actual path to your newly created +# .gitignore_global file: +# git config --global core.excludesfile path/to/your/.gitignore_global + +# CircuitPython-specific files *.mpy -.idea + +# Python-specific files __pycache__ -_build *.pyc + +# Sphinx build-specific files +_build + +# This file results from running `pip -e install .` in a local repository +*.egg-info + +# Virtual environment-specific files .env -.python-version -build*/ -bundles + +# MacOS-specific files *.DS_Store -.eggs -dist -**/*.egg-info + +# IDE-specific files +.idea .vscode +*~ From 25996804ce42233784a293481a9cb4aeba2490d7 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Fri, 22 Apr 2022 15:58:33 -0400 Subject: [PATCH 044/132] Patch: Replaced discord badge image --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6403d92..849ce03 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Introduction :target: https://docs.circuitpython.org/projects/displayio-layout/en/latest/ :alt: Documentation Status -.. image:: https://img.shields.io/discord/327254708534116352.svg +.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Bundle/blob/main/badges/adafruit_discord.svg :target: https://adafru.it/discord :alt: Discord From a5865ee634950234259387a29ba409c07a787d73 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 24 Apr 2022 14:03:23 -0500 Subject: [PATCH 045/132] change discord badge --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 849ce03..b7564a2 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Introduction :target: https://docs.circuitpython.org/projects/displayio-layout/en/latest/ :alt: Documentation Status -.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Bundle/blob/main/badges/adafruit_discord.svg +.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg :target: https://adafru.it/discord :alt: Discord From b290f05afd0852d2b666d2d127b75f0ea546aa9b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 29 Apr 2022 18:32:39 -0500 Subject: [PATCH 046/132] starting tab layout --- .../layouts/tab_layout.py | 182 ++++++++++++++++ examples/displayio_layout_tab_layout_test.py | 199 ++++++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 adafruit_displayio_layout/layouts/tab_layout.py create mode 100644 examples/displayio_layout_tab_layout_test.py diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py new file mode 100644 index 0000000..c40b925 --- /dev/null +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -0,0 +1,182 @@ + +try: + from typing import Optional, Union + from fontio import BuiltinFont + from adafruit_bitmap_font.bdf import BDF + from adafruit_bitmap_font.pcf import PCF +except ImportError: + pass + +import board +import terminalio +import displayio +import adafruit_imageload +from adafruit_display_text.bitmap_label import Label +from adafruit_imageload.tilegrid_inflator import inflate_tilegrid +from adafruit_displayio_layout.layouts.page_layout import PageLayout + +class TabLayout(displayio.Group): + def __init__(self, + x: int = 0, y: int = 0, + display: displayio.Display = board.DISPLAY, + tab_text_scale: int = 1, + custom_font: Optional[Union[BuiltinFont, BDF, PCF]] = terminalio.FONT, + inactive_tab_spritesheet: Optional[str] = None, + active_tab_spritesheet: Optional[str] = None, + active_tab_text_color: Optional[int, tuple[int, int, int]] = 0x999999, + inactive_tab_text_color: Optional[int, tuple[int, int, int]] = 0xfffff, + inactive_tab_transparent_indexes: Optional[Union[int, tuple[int, int]]] = None, + active_tab_transparent_indexes: Optional[Union[int, tuple[int, int]]] = None, + tab_count: int = None, + ): + + if inactive_tab_spritesheet is None: + raise AttributeError("Must pass active_tab_spritesheet") + if active_tab_spritesheet is None: + raise AttributeError("Must pass inactive_tab_spritesheet") + if tab_count is None: + raise AttributeError("Must pass tab_count") + + super().__init__(x=x, y=y) + self.tab_count = tab_count + self._active_bmp, self._active_palette = adafruit_imageload.load(active_tab_spritesheet) + self._inactive_bmp, self._inactive_palette = adafruit_imageload.load(inactive_tab_spritesheet) + + if isinstance(active_tab_transparent_indexes, int): + self._active_palette.make_transparent(active_tab_transparent_indexes) + elif isinstance(active_tab_transparent_indexes, tuple): + for index in active_tab_transparent_indexes: + self._active_palette.make_transparent(index) + else: + raise AttributeError("active_tab_transparent_indexes must be int or tuple") + + if isinstance(inactive_tab_transparent_indexes, int): + self._inactive_palette.make_transparent(inactive_tab_transparent_indexes) + elif isinstance(inactive_tab_transparent_indexes, tuple): + for index in inactive_tab_transparent_indexes: + self._inactive_palette.make_transparent(index) + else: + raise AttributeError("inactive_tab_transparent_indexes must be int or tuple") + + self.tab_height = self._active_bmp.height + self.display = display + self.active_tab_text_color = active_tab_text_color + self.inactive_tab_text_color = inactive_tab_text_color + self.custom_font = custom_font + self.tab_text_scale = tab_text_scale + self.tab_group = displayio.Group() + self.tab_dict = {} + self.page_layout = PageLayout(x=x, y=y + self.tab_height) + + self.append(self.tab_group) + self.append(self.page_layout) + + def _draw_tabs(self): + for i, page_dict in enumerate(self.page_layout._page_content_list): + if i not in self.tab_dict: + print(f"creating tab {i}") + _new_tab_group = displayio.Group() + _tab_tilegrid = inflate_tilegrid(bmp_obj=self._inactive_bmp, bmp_palette=self._inactive_palette, + target_size=((self.display.width // self.tab_count) // ( + self._active_bmp.width // 3), 3)) + + _tab_tilegrid.x = (self.display.width // self.tab_count) * i + _new_tab_group.append(_tab_tilegrid) + + _tab_label = Label(self.custom_font, text=page_dict["page_name"], + color=self.inactive_tab_text_color, scale=self.tab_text_scale) + + _tab_label.anchor_point = (0.5, 0.5) + _tab_label.anchored_position = ( + _tab_tilegrid.x + + ((_tab_tilegrid.width * _tab_tilegrid.tile_width) // 2), + (_tab_tilegrid.height * _tab_tilegrid.tile_height) // 2 + ) + _new_tab_group.append(_tab_label) + + if i == self.page_layout.showing_page_index: + _tab_tilegrid.bitmap = self._active_bmp + _tab_tilegrid.pixel_shader = self._active_palette + _tab_label.color = self.active_tab_text_color + self.tab_dict[i] = _new_tab_group + self.tab_group.append(_new_tab_group) + + def _update_active_tab(self): + for i in range(len(self.page_layout)): + if i == self.page_layout.showing_page_index: + self.tab_group[i][0].bitmap = self._active_bmp + self.tab_group[i][0].pixel_shader = self._active_palette + self.tab_group[i][1].color = self.active_tab_text_color + else: + self.tab_group[i][0].bitmap = self._inactive_bmp + self.tab_group[i][0].pixel_shader = self._inactive_palette + self.tab_group[i][1].color = self.inactive_tab_text_color + + def add_content(self, tab_content, tab_name): + self.page_layout.add_content(tab_content, tab_name) + self._draw_tabs() + + + def show_page(self, page_name=None, page_index=None): + """ + Show the specified page, and hide all other pages. + + :param string page_name: The name of a page to show + :param int page_index: The index of a page to show + :return: None + """ + + self.page_layout.show_page(page_name=page_name, page_index=page_index) + self._update_active_tab() + + + @property + def showing_page_index(self): + """ + Index of the currently showing page + :return int: showing_page_index + """ + return self.page_layout.showing_page_index + + @showing_page_index.setter + def showing_page_index(self, new_index): + self.show_page(page_index=new_index) + + @property + def showing_page_name(self): + """ + Name of the currently showing page + :return string: showing_page_name + """ + return self.page_layout.showing_page_name + + @showing_page_name.setter + def showing_page_name(self, new_name): + self.show_page(page_name=new_name) + + @property + def showing_page_content(self): + """ + The content object for the currently showing page + :return Displayable: showing_page_content + """ + return self.page_layout.showing_page_content + + def next_page(self, loop=True): + """ + Hide the current page and show the next one in the list by index + :param bool loop: whether to loop from the last page back to the first + :return: None + """ + + self.page_layout.next_page(loop=loop) + self._update_active_tab() + + def previous_page(self, loop=True): + """ + Hide the current page and show the previous one in the list by index + :param bool loop: whether to loop from the first page to the last one + :return: None + """ + self.page_layout.previous_page(loop=loop) + self._update_active_tab() diff --git a/examples/displayio_layout_tab_layout_test.py b/examples/displayio_layout_tab_layout_test.py new file mode 100644 index 0000000..1942d3a --- /dev/null +++ b/examples/displayio_layout_tab_layout_test.py @@ -0,0 +1,199 @@ +# import time +# import displayio +# import board +# import terminalio +# from adafruit_displayio_layout.layouts.page_layout import PageLayout +# from adafruit_display_text.bitmap_label import Label +# import vectorio +# +# display = board.DISPLAY +# +# # Make the display context +# main_group = displayio.Group() +# display.show(main_group) +# +# test_page_layout = PageLayout(x=0, y=0) +# +# page_1_lbl = Label(font=terminalio.FONT, text="Page One!", anchor_point=(0, 0), anchored_position=(10, 10), scale=3) +# page_2_lbl = Label(font=terminalio.FONT, text="Page Two!", anchor_point=(0, 0), anchored_position=(10, 10), scale=3) +# other_lbl = Label(font=terminalio.FONT, text="Something Different!", anchor_point=(0, 0), anchored_position=(10, 50), scale=3) +# +# test_page_layout.add_content(page_1_lbl, "page_1") +# test_page_layout.add_content(page_2_lbl, "page_2") +# test_page_layout.add_content(other_lbl, "page_3") +# +# #main_group.append(other_lbl) +# +# main_group.append(test_page_layout) +# +# print("showing page 1") +# +# test_page_layout.show_page(page_name="page_2") +# +# +# test_page_layout.showing_page_index = 0 +# +# #print(test_page_layout.showing_page_index) +# #print(test_page_layout.showing_page_name) +# +# colors = displayio.Palette(3) +# colors[0] = 0xdddd00 +# colors[1] = 0x00dddd +# colors[2] = 0x00dd00 +# rect = vectorio.Rectangle(pixel_shader=colors, width=100,height=20, x=10, y=100) +# +# test_page_layout.get_page(page_index=2)["content"][0].color = 0xFF00FF +# test_page_layout.get_page(page_name="page_2")["content"].append(rect) +# +# while True: +# time.sleep(1) +# test_page_layout.previous_page() +# +# +# # test_page_layout.show_page(page_name="page_1") +# # time.sleep(1) +# # test_page_layout.show_page(page_name="page_2") +# # time.sleep(1) +# pass + + +# SPDX-FileCopyrightText: 2022 Tim C +# +# SPDX-License-Identifier: MIT +""" +Make a PageLayout and illustrate all of it's features +""" +import time +import displayio +import board +import terminalio +from adafruit_display_text.bitmap_label import Label +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.triangle import Triangle +from adafruit_displayio_layout.layouts.tab_layout import TabLayout +from adafruit_bitmap_font import bitmap_font + +# built-in display +display = board.DISPLAY +# display.rotation = 90 +display.rotation = 0 + +# create and show main_group +main_group = displayio.Group() +display.show(main_group) + +font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") + +# create the page layout +test_page_layout = TabLayout(x=0, y=0, + display=board.DISPLAY, + tab_height=28, tab_text_scale=1, + custom_font=font, + inactive_tab_spritesheet="bmps/test_bmp_6.bmp", + active_tab_spritesheet="bmps/test_bmp_7.bmp", + showing_tab_text_color=0x00aa59, + tab_text_color=0xeeeeee, + inactive_tab_transparent_indexes=(0, 1), + active_tab_transparent_indexes=(0, 1), + tab_count=4) + +# make 3 pages of content +page_1_group = displayio.Group() +page_2_group = displayio.Group() +page_3_group = displayio.Group() +page_4_group = displayio.Group() + +# labels +page_1_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This is the first page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_2_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This page is the second page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_3_lbl = Label( + font=terminalio.FONT, + scale=2, + text="The third page is fun!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) + +page_4_lbl = Label( + font=terminalio.FONT, + scale=2, + text="The fourth page is where it's at", + anchor_point=(0, 0), + anchored_position=(10, 10), +) + +# shapes +square = Rect(x=20, y=70, width=40, height=40, fill=0x00DD00) +circle = Circle(50, 100, r=30, fill=0xDD00DD) +triangle = Triangle(50, 0, 100, 50, 0, 50, fill=0xDDDD00) +rectangle = Rect(x=80, y=60, width=100, height=50, fill=0x0000DD) + +triangle.x = 80 +triangle.y = 70 + +# add everything to their page groups +page_1_group.append(square) +page_1_group.append(page_1_lbl) +page_2_group.append(page_2_lbl) +page_2_group.append(circle) +page_3_group.append(page_3_lbl) +page_3_group.append(triangle) +page_4_group.append(page_4_lbl) +page_4_group.append(rectangle) + +# add the pages to the layout, supply your own page names +test_page_layout.add_content(page_1_group, "One") +test_page_layout.add_content(page_2_group, "Two") +test_page_layout.add_content(page_3_group, "Thr") +test_page_layout.add_content(page_4_group, "For") +# test_page_layout.add_content(displayio.Group(), "page_5") + +# add it to the group that is showing on the display +main_group.append(test_page_layout) + +#test_page_layout.tab_tilegrids_group[3].x += 50 + +# change page with function by name +# test_page_layout.show_page(page_name="page_3") +# print("showing page index:{}".format(test_page_layout.showing_page_index)) +# time.sleep(1) + +# change page with function by index +test_page_layout.show_page(page_index=0) +print("showing page name: {}".format(test_page_layout.showing_page_name)) +time.sleep(1) + +# change page by updating the page name property +# test_page_layout.showing_page_name = "page_3" +# print("showing page index: {}".format(test_page_layout.showing_page_index)) +# time.sleep(1) + +# change page by updating the page index property +test_page_layout.showing_page_index = 1 +print("showing page name: {}".format(test_page_layout.showing_page_name)) +time.sleep(5) + +another_text = Label(terminalio.FONT, text="And another thing!", scale=2, color=0x00ff00, anchor_point=(0, 0), + anchored_position=(100, 100)) +test_page_layout.showing_page_content.append(another_text) + +print("starting loop") + + +while True: + time.sleep(1) + # change page by next page function. It will loop by default + test_page_layout.next_page() From 2b9aaa134d4645e155e1c0e00679ba888c2c810d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 30 Apr 2022 06:09:57 -0500 Subject: [PATCH 047/132] change to default font and add sprites to exampes dir --- examples/bmps/test_bmp_6.bmp | Bin 0 -> 1738 bytes examples/bmps/test_bmp_7.bmp | Bin 0 -> 1730 bytes examples/displayio_layout_tab_layout_test.py | 24 ++++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 examples/bmps/test_bmp_6.bmp create mode 100644 examples/bmps/test_bmp_7.bmp diff --git a/examples/bmps/test_bmp_6.bmp b/examples/bmps/test_bmp_6.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ab415097779b7f14ab1768f930e80f266fec6b18 GIT binary patch literal 1738 zcmZ?rJ;lZV2B&~z4G`M^u>lY>GOz$iAOOlM>p`#pkPE^L4F6#W%yV)NDh4x1Aehk9 z{s)@*pYcC~zrR0&e}ErDK&&@IP`(R8P@ywJP^lwBaDxp)NUH@y*i;>c@YyO1k*gRO zB9@3T#IBTNs8|%iaORK_PM~v!fw25xoZ6MZ`UhH`QvXq?{|&AEPoeuLj{i~nm2d%~ z^3PBYzazMOucYJyDnE|mmX86-|2c_Ue$IIY2ACveI4faQ747GYPQeg|Yc&;d8F%lCq<2U>7u88!u3XTZjT3^=nh1YL#e>@!g9 fUlY>GOz$iAOOlM>p?IdkPE^L4F6#W%yV)NDh4x1Aehk9 z{s)@*pAl#-5CrABFa#AkGX#}7G6Xl+Fod*PFoaFjVF;hC!VtNNfgxgv7(?tzNrs9= z5e%yqDd7ZKK((XtID Date: Fri, 6 May 2022 18:10:14 -0500 Subject: [PATCH 048/132] working on tab_layout and simpletest example --- .../layouts/page_layout.py | 28 ++-- .../layouts/tab_layout.py | 155 ++++++++++++++---- docs/api.rst | 12 ++ .../{test_bmp_7.bmp => active_tab_sprite.bmp} | Bin examples/bmps/active_tab_sprite.bmp.license | 2 + ...test_bmp_6.bmp => inactive_tab_sprite.bmp} | Bin examples/bmps/inactive_tab_sprite.bmp.license | 2 + examples/displayio_layout_tab_layout_test.py | 127 +++++--------- 8 files changed, 192 insertions(+), 134 deletions(-) rename examples/bmps/{test_bmp_7.bmp => active_tab_sprite.bmp} (100%) create mode 100644 examples/bmps/active_tab_sprite.bmp.license rename examples/bmps/{test_bmp_6.bmp => inactive_tab_sprite.bmp} (100%) create mode 100644 examples/bmps/inactive_tab_sprite.bmp.license diff --git a/adafruit_displayio_layout/layouts/page_layout.py b/adafruit_displayio_layout/layouts/page_layout.py index bee92ba..1dc1798 100644 --- a/adafruit_displayio_layout/layouts/page_layout.py +++ b/adafruit_displayio_layout/layouts/page_layout.py @@ -53,11 +53,11 @@ def __init__( self.x = x self.y = y - self._page_content_list = [] + self.page_content_list = [] self._cur_showing_index = 0 def add_content(self, page_content, page_name=None): - """Add a child to the grid. + """Add a child to the page layout. :param page_content: the content for the page typically a Group :param page_name: the name of this page @@ -72,10 +72,10 @@ def add_content(self, page_content, page_name=None): "page_name": page_name, } - if len(self._page_content_list) > 0: + if len(self.page_content_list) > 0: _page_group.hidden = True - self._page_content_list.append(sub_view_obj) + self.page_content_list.append(sub_view_obj) self.append(_page_group) def _check_args(self, page_name, page_index): @@ -95,16 +95,16 @@ def _check_args(self, page_name, page_index): ) if page_index is not None: - if page_index >= len(self._page_content_list): + if page_index >= len(self.page_content_list): raise KeyError( "KeyError at index {} in list length {}".format( - page_index, len(self._page_content_list) + page_index, len(self.page_content_list) ), ) if page_name is not None: _found = False - for page in self._page_content_list: + for page in self.page_content_list: if not _found: if page_name == page["page_name"]: _found = True @@ -125,10 +125,10 @@ def get_page(self, page_name=None, page_index=None): self._check_args(page_name, page_index) if page_index is not None: - return self._page_content_list[page_index] + return self.page_content_list[page_index] if page_name is not None: - for cell in self._page_content_list: + for cell in self.page_content_list: if cell["page_name"] == page_name: return cell @@ -149,7 +149,7 @@ def show_page(self, page_name=None, page_index=None): self._check_args(page_name, page_index) - for cur_index, page in enumerate(self._page_content_list): + for cur_index, page in enumerate(self.page_content_list): if page_name is not None: if page["page_name"] == page_name: self._cur_showing_index = cur_index @@ -182,7 +182,7 @@ def showing_page_name(self): Name of the currently showing page :return string: showing_page_name """ - return self._page_content_list[self._cur_showing_index]["page_name"] + return self.page_content_list[self._cur_showing_index]["page_name"] @showing_page_name.setter def showing_page_name(self, new_name): @@ -194,7 +194,7 @@ def showing_page_content(self): The content object for the currently showing page :return Displayable: showing_page_content """ - return self._page_content_list[self._cur_showing_index]["content"][0] + return self.page_content_list[self._cur_showing_index]["content"][0] def next_page(self, loop=True): """ @@ -203,7 +203,7 @@ def next_page(self, loop=True): :return: None """ - if self._cur_showing_index + 1 < len(self._page_content_list): + if self._cur_showing_index + 1 < len(self.page_content_list): self.show_page(page_index=self._cur_showing_index + 1) else: if not loop: @@ -223,4 +223,4 @@ def previous_page(self, loop=True): if not loop: print("No more pages") else: - self.show_page(page_index=len(self._page_content_list) - 1) + self.show_page(page_index=len(self.page_content_list) - 1) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index c40b925..61c7d76 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -1,13 +1,35 @@ +# SPDX-FileCopyrightText: 2022 Tim Cocks +# +# SPDX-License-Identifier: MIT +""" +`tab_layout` +================================================================================ + +A layout that organizes pages into tabs. + + +* Author(s): Tim Cocks + +Implementation Notes +-------------------- + +**Hardware:** + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://github.com/adafruit/circuitpython/releases + +""" try: - from typing import Optional, Union + from typing import Optional, Union, Tuple from fontio import BuiltinFont from adafruit_bitmap_font.bdf import BDF from adafruit_bitmap_font.pcf import PCF except ImportError: pass -import board import terminalio import displayio import adafruit_imageload @@ -15,21 +37,55 @@ from adafruit_imageload.tilegrid_inflator import inflate_tilegrid from adafruit_displayio_layout.layouts.page_layout import PageLayout + class TabLayout(displayio.Group): - def __init__(self, - x: int = 0, y: int = 0, - display: displayio.Display = board.DISPLAY, - tab_text_scale: int = 1, - custom_font: Optional[Union[BuiltinFont, BDF, PCF]] = terminalio.FONT, - inactive_tab_spritesheet: Optional[str] = None, - active_tab_spritesheet: Optional[str] = None, - active_tab_text_color: Optional[int, tuple[int, int, int]] = 0x999999, - inactive_tab_text_color: Optional[int, tuple[int, int, int]] = 0xfffff, - inactive_tab_transparent_indexes: Optional[Union[int, tuple[int, int]]] = None, - active_tab_transparent_indexes: Optional[Union[int, tuple[int, int]]] = None, - tab_count: int = None, - ): + """ + A layout that organizes children into a grid table structure. + + :param int x: x location the layout should be placed. Pixel coordinates. + :param int y: y location the layout should be placed. Pixel coordinates. + :param displayio.Display display: The Display object to show the tab layout on. + :param int tab_text_scale: Size of the text shown in the tabs. + Whole numbers 1 and greater are valid + :param Optional[Union[BuiltinFont, BDF, PCF]] custom_font: A pre-loaded font object to use + for the tab labels + :param str inactive_tab_spritesheet: Filepath of the spritesheet to show for inactive tabs. + :param str active_tab_spritesheet: Filepath of the spritesheet to show for the active tab. + :param Optional[int, tuple[int, int, int]] active_tab_text_color: Hex or tuple color to use + for the active tab label + :param Optional[int, tuple[int, int, int]] inactive_tab_text_color: Hex or tuple color to + use for inactive tab labels + :param Optional[Union[int, tuple[int, int]]] inactive_tab_transparent_indexes: single index + or tuple of multiple indexes to be made transparent in the inactive tab sprite palette. + :param Optional[Union[int, tuple[int, int]]] active_tab_transparent_indexes: single index + or tuple of multiple indexes to be made transparent in the active tab sprite palette. + :param int tab_count: How many tabs to draw in the layout. Positive whole numbers are valid. + """ + + # pylint: disable=too-many-instance-attributes, too-many-arguments, invalid-name, too-many-branches + def __init__( + self, + x: int = 0, + y: int = 0, + display: Optional[displayio.Display] = None, + tab_text_scale: int = 1, + custom_font: Optional[Union[BuiltinFont, BDF, PCF]] = terminalio.FONT, + inactive_tab_spritesheet: Optional[str] = None, + active_tab_spritesheet: Optional[str] = None, + active_tab_text_color: Optional[Union[int, Tuple[int, int, int]]] = 0x999999, + inactive_tab_text_color: Optional[Union[int, Tuple[int, int, int]]] = 0xFFFFF, + inactive_tab_transparent_indexes: Optional[Union[int, Tuple[int, int]]] = None, + active_tab_transparent_indexes: Optional[Union[int, Tuple[int, int]]] = None, + tab_count: int = None, + ): + + if display is None: + # pylint: disable=import-outside-toplevel + import board + + if hasattr(board, "DISPLAY"): + display = board.DISPLAY if inactive_tab_spritesheet is None: raise AttributeError("Must pass active_tab_spritesheet") if active_tab_spritesheet is None: @@ -39,8 +95,12 @@ def __init__(self, super().__init__(x=x, y=y) self.tab_count = tab_count - self._active_bmp, self._active_palette = adafruit_imageload.load(active_tab_spritesheet) - self._inactive_bmp, self._inactive_palette = adafruit_imageload.load(inactive_tab_spritesheet) + self._active_bmp, self._active_palette = adafruit_imageload.load( + active_tab_spritesheet + ) + self._inactive_bmp, self._inactive_palette = adafruit_imageload.load( + inactive_tab_spritesheet + ) if isinstance(active_tab_transparent_indexes, int): self._active_palette.make_transparent(active_tab_transparent_indexes) @@ -56,7 +116,9 @@ def __init__(self, for index in inactive_tab_transparent_indexes: self._inactive_palette.make_transparent(index) else: - raise AttributeError("inactive_tab_transparent_indexes must be int or tuple") + raise AttributeError( + "inactive_tab_transparent_indexes must be int or tuple" + ) self.tab_height = self._active_bmp.height self.display = display @@ -72,25 +134,35 @@ def __init__(self, self.append(self.page_layout) def _draw_tabs(self): - for i, page_dict in enumerate(self.page_layout._page_content_list): + for i, page_dict in enumerate(self.page_layout.page_content_list): if i not in self.tab_dict: print(f"creating tab {i}") _new_tab_group = displayio.Group() - _tab_tilegrid = inflate_tilegrid(bmp_obj=self._inactive_bmp, bmp_palette=self._inactive_palette, - target_size=((self.display.width // self.tab_count) // ( - self._active_bmp.width // 3), 3)) + _tab_tilegrid = inflate_tilegrid( + bmp_obj=self._inactive_bmp, + bmp_palette=self._inactive_palette, + target_size=( + (self.display.width // self.tab_count) + // (self._active_bmp.width // 3), + 3, + ), + ) _tab_tilegrid.x = (self.display.width // self.tab_count) * i _new_tab_group.append(_tab_tilegrid) - _tab_label = Label(self.custom_font, text=page_dict["page_name"], - color=self.inactive_tab_text_color, scale=self.tab_text_scale) + _tab_label = Label( + self.custom_font, + text=page_dict["page_name"], + color=self.inactive_tab_text_color, + scale=self.tab_text_scale, + ) _tab_label.anchor_point = (0.5, 0.5) _tab_label.anchored_position = ( - _tab_tilegrid.x + - ((_tab_tilegrid.width * _tab_tilegrid.tile_width) // 2), - (_tab_tilegrid.height * _tab_tilegrid.tile_height) // 2 + _tab_tilegrid.x + + ((_tab_tilegrid.width * _tab_tilegrid.tile_width) // 2), + (_tab_tilegrid.height * _tab_tilegrid.tile_height) // 2, ) _new_tab_group.append(_tab_label) @@ -113,10 +185,15 @@ def _update_active_tab(self): self.tab_group[i][1].color = self.inactive_tab_text_color def add_content(self, tab_content, tab_name): + """Add a child to the tab layout. + + :param tab_content: the content for the tab typically a Group + :param tab_name: the name of this tab, will be shown inside the tab + + :return: None""" self.page_layout.add_content(tab_content, tab_name) self._draw_tabs() - def show_page(self, page_name=None, page_index=None): """ Show the specified page, and hide all other pages. @@ -129,7 +206,6 @@ def show_page(self, page_name=None, page_index=None): self.page_layout.show_page(page_name=page_name, page_index=page_index) self._update_active_tab() - @property def showing_page_index(self): """ @@ -140,7 +216,8 @@ def showing_page_index(self): @showing_page_index.setter def showing_page_index(self, new_index): - self.show_page(page_index=new_index) + if self.showing_page_index != new_index: + self.show_page(page_index=new_index) @property def showing_page_name(self): @@ -180,3 +257,21 @@ def previous_page(self, loop=True): """ self.page_layout.previous_page(loop=loop) self._update_active_tab() + + def handle_touch_events(self, touch_event): + """ + Check if the touch event is on the tabs and if so change to the touched tab. + + :param tuple touch_event: tuple containing x and y coordinates of the + touch event in indexes 0 and 1. + :return: None + """ + + if touch_event: + if 0 <= touch_event[1] <= self.tab_height: + + touched_tab_index = touch_event[0] // ( + self.display.width // self.tab_count + ) + print(f"{touch_event[0]} - {touched_tab_index}") + self.showing_page_index = touched_tab_index diff --git a/docs/api.rst b/docs/api.rst index b517167..a707e30 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -6,6 +6,18 @@ .. automodule:: adafruit_displayio_layout.layouts.grid_layout :members: + :private-members: + :member-order: bysource + +.. automodule:: adafruit_displayio_layout.layouts.page_layout + :members: + :private-members: + :member-order: bysource + +.. automodule:: adafruit_displayio_layout.layouts.tab_layout + :members: + :private-members: + :member-order: bysource .. automodule:: adafruit_displayio_layout.widgets.widget :members: diff --git a/examples/bmps/test_bmp_7.bmp b/examples/bmps/active_tab_sprite.bmp similarity index 100% rename from examples/bmps/test_bmp_7.bmp rename to examples/bmps/active_tab_sprite.bmp diff --git a/examples/bmps/active_tab_sprite.bmp.license b/examples/bmps/active_tab_sprite.bmp.license new file mode 100644 index 0000000..8f7990c --- /dev/null +++ b/examples/bmps/active_tab_sprite.bmp.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2022 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT diff --git a/examples/bmps/test_bmp_6.bmp b/examples/bmps/inactive_tab_sprite.bmp similarity index 100% rename from examples/bmps/test_bmp_6.bmp rename to examples/bmps/inactive_tab_sprite.bmp diff --git a/examples/bmps/inactive_tab_sprite.bmp.license b/examples/bmps/inactive_tab_sprite.bmp.license new file mode 100644 index 0000000..8f7990c --- /dev/null +++ b/examples/bmps/inactive_tab_sprite.bmp.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2022 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT diff --git a/examples/displayio_layout_tab_layout_test.py b/examples/displayio_layout_tab_layout_test.py index c79ab3c..6759f5e 100644 --- a/examples/displayio_layout_tab_layout_test.py +++ b/examples/displayio_layout_tab_layout_test.py @@ -1,67 +1,8 @@ -# import time -# import displayio -# import board -# import terminalio -# from adafruit_displayio_layout.layouts.page_layout import PageLayout -# from adafruit_display_text.bitmap_label import Label -# import vectorio -# -# display = board.DISPLAY -# -# # Make the display context -# main_group = displayio.Group() -# display.show(main_group) -# -# test_page_layout = PageLayout(x=0, y=0) -# -# page_1_lbl = Label(font=terminalio.FONT, text="Page One!", anchor_point=(0, 0), anchored_position=(10, 10), scale=3) -# page_2_lbl = Label(font=terminalio.FONT, text="Page Two!", anchor_point=(0, 0), anchored_position=(10, 10), scale=3) -# other_lbl = Label(font=terminalio.FONT, text="Something Different!", anchor_point=(0, 0), anchored_position=(10, 50), scale=3) - -# test_page_layout.add_content(page_1_lbl, "page_1") -# test_page_layout.add_content(page_2_lbl, "page_2") -# test_page_layout.add_content(other_lbl, "page_3") -# -# #main_group.append(other_lbl) -# -# main_group.append(test_page_layout) -# -# print("showing page 1") -# -# test_page_layout.show_page(page_name="page_2") -# -# -# test_page_layout.showing_page_index = 0 -# -# #print(test_page_layout.showing_page_index) -# #print(test_page_layout.showing_page_name) -# -# colors = displayio.Palette(3) -# colors[0] = 0xdddd00 -# colors[1] = 0x00dddd -# colors[2] = 0x00dd00 -# rect = vectorio.Rectangle(pixel_shader=colors, width=100,height=20, x=10, y=100) -# -# test_page_layout.get_page(page_index=2)["content"][0].color = 0xFF00FF -# test_page_layout.get_page(page_name="page_2")["content"].append(rect) -# -# while True: -# time.sleep(1) -# test_page_layout.previous_page() -# -# -# # test_page_layout.show_page(page_name="page_1") -# # time.sleep(1) -# # test_page_layout.show_page(page_name="page_2") -# # time.sleep(1) -# pass - - # SPDX-FileCopyrightText: 2022 Tim C # # SPDX-License-Identifier: MIT """ -Make a PageLayout and illustrate all of it's features +Make a TabLayout and illustrate the most basic features and usage. """ import time import displayio @@ -72,34 +13,35 @@ from adafruit_display_shapes.circle import Circle from adafruit_display_shapes.triangle import Triangle from adafruit_displayio_layout.layouts.tab_layout import TabLayout -from adafruit_bitmap_font import bitmap_font + +CHANGE_DELAY = 1.0 # Seconds to wait before auto-advancing to the next tab # built-in display display = board.DISPLAY -# display.rotation = 90 -display.rotation = 0 # create and show main_group main_group = displayio.Group() display.show(main_group) -#font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") font = terminalio.FONT # create the page layout -test_page_layout = TabLayout(x=0, y=0, - display=board.DISPLAY, - tab_text_scale=2, - custom_font=font, - inactive_tab_spritesheet="bmps/test_bmp_6.bmp", - active_tab_spritesheet="bmps/test_bmp_7.bmp", - active_tab_text_color=0x00aa59, - inactive_tab_text_color=0xeeeeee, - inactive_tab_transparent_indexes=(0, 1), - active_tab_transparent_indexes=(0, 1), - tab_count=4) - -# make 3 pages of content +test_page_layout = TabLayout( + x=0, + y=0, + display=board.DISPLAY, + tab_text_scale=2, + custom_font=font, + inactive_tab_spritesheet="bmps/inactive_tab_sprite.bmp", + active_tab_spritesheet="bmps/active_tab_sprite.bmp", + active_tab_text_color=0x00AA59, + inactive_tab_text_color=0xEEEEEE, + inactive_tab_transparent_indexes=(0, 1), + active_tab_transparent_indexes=(0, 1), + tab_count=4, +) + +# make page content Groups page_1_group = displayio.Group() page_2_group = displayio.Group() page_3_group = displayio.Group() @@ -116,7 +58,7 @@ page_2_lbl = Label( font=terminalio.FONT, scale=2, - text="This page is the second page!", + text="This page is the\nsecond page!", anchor_point=(0, 0), anchored_position=(10, 10), ) @@ -131,16 +73,16 @@ page_4_lbl = Label( font=terminalio.FONT, scale=2, - text="The fourth page is where it's at", + text="The fourth page\nis where it's at", anchor_point=(0, 0), anchored_position=(10, 10), ) # shapes square = Rect(x=20, y=70, width=40, height=40, fill=0x00DD00) -circle = Circle(50, 100, r=30, fill=0xDD00DD) +circle = Circle(50, 120, r=30, fill=0xDD00DD) triangle = Triangle(50, 0, 100, 50, 0, 50, fill=0xDDDD00) -rectangle = Rect(x=80, y=60, width=100, height=50, fill=0x0000DD) +rectangle = Rect(x=80, y=80, width=100, height=50, fill=0x0000DD) triangle.x = 80 triangle.y = 70 @@ -160,13 +102,10 @@ test_page_layout.add_content(page_2_group, "Two") test_page_layout.add_content(page_3_group, "Thr") test_page_layout.add_content(page_4_group, "For") -# test_page_layout.add_content(displayio.Group(), "page_5") # add it to the group that is showing on the display main_group.append(test_page_layout) -#test_page_layout.tab_tilegrids_group[3].x += 50 - # change page with function by name test_page_layout.show_page(page_name="Thr") print("showing page index:{}".format(test_page_layout.showing_page_index)) @@ -187,15 +126,23 @@ print("showing page name: {}".format(test_page_layout.showing_page_name)) time.sleep(5) -another_text = Label(terminalio.FONT, text="And another thing!", scale=2, color=0x00ff00, anchor_point=(0, 0), - anchored_position=(100, 100)) +another_text = Label( + terminalio.FONT, + text="And another thing!", + scale=2, + color=0x00FF00, + anchor_point=(0, 0), + anchored_position=(100, 100), +) test_page_layout.showing_page_content.append(another_text) print("starting loop") +prev_change_time = time.monotonic() while True: - time.sleep(1) - # change page by next page function. It will loop by default - test_page_layout.next_page() - pass + now = time.monotonic() + if prev_change_time + CHANGE_DELAY <= now: + prev_change_time = now + # change page by next page function. It will loop by default + test_page_layout.next_page() From bdb03c95009b1a4a53e130ffa6f9c5fb01702ea2 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 6 May 2022 18:18:43 -0500 Subject: [PATCH 049/132] rename to simpletest --- ...b_layout_test.py => displayio_layout_tab_layout_simpletest.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{displayio_layout_tab_layout_test.py => displayio_layout_tab_layout_simpletest.py} (100%) diff --git a/examples/displayio_layout_tab_layout_test.py b/examples/displayio_layout_tab_layout_simpletest.py similarity index 100% rename from examples/displayio_layout_tab_layout_test.py rename to examples/displayio_layout_tab_layout_simpletest.py From 801bdcb23e8dca18d3b55768f5957abfef634527 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 6 May 2022 20:59:31 -0500 Subject: [PATCH 050/132] tab layout touch example --- .../displayio_layout_tab_layout_touchtest.py | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 examples/displayio_layout_tab_layout_touchtest.py diff --git a/examples/displayio_layout_tab_layout_touchtest.py b/examples/displayio_layout_tab_layout_touchtest.py new file mode 100644 index 0000000..d8cd5bf --- /dev/null +++ b/examples/displayio_layout_tab_layout_touchtest.py @@ -0,0 +1,137 @@ +# SPDX-FileCopyrightText: 2022 Tim C +# +# SPDX-License-Identifier: MIT +""" +Make a TabLayout change tabs with the touchscreen +""" +import displayio +import board +import terminalio +import adafruit_touchscreen +from adafruit_display_text.bitmap_label import Label +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.triangle import Triangle +from adafruit_displayio_layout.layouts.tab_layout import TabLayout + +# built-in display +display = board.DISPLAY + +# ------------ Touchscreen setup --------------- # +# See: https://learn.adafruit.com/making-a-pyportal-user-interface-displayio/display +display = board.DISPLAY # create the display object + +screen_width = display.width +screen_height = display.height +ts = adafruit_touchscreen.Touchscreen( + board.TOUCH_XL, + board.TOUCH_XR, + board.TOUCH_YD, + board.TOUCH_YU, + calibration=((5200, 59000), (5800, 57000)), + size=(screen_width, screen_height), +) + +# create and show main_group +main_group = displayio.Group() +display.show(main_group) + +font = terminalio.FONT + +# create the page layout +test_page_layout = TabLayout( + x=0, + y=0, + display=board.DISPLAY, + tab_text_scale=2, + custom_font=font, + inactive_tab_spritesheet="bmps/inactive_tab_sprite.bmp", + active_tab_spritesheet="bmps/active_tab_sprite.bmp", + active_tab_text_color=0x00AA59, + inactive_tab_text_color=0xEEEEEE, + inactive_tab_transparent_indexes=(0, 1), + active_tab_transparent_indexes=(0, 1), + tab_count=4, +) + +# make page content Groups +page_1_group = displayio.Group() +page_2_group = displayio.Group() +page_3_group = displayio.Group() +page_4_group = displayio.Group() + +# labels +page_1_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This is the first page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_2_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This page is the\nsecond page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +page_3_lbl = Label( + font=terminalio.FONT, + scale=2, + text="The third page is fun!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) + +page_4_lbl = Label( + font=terminalio.FONT, + scale=2, + text="The fourth page\nis where it's at", + anchor_point=(0, 0), + anchored_position=(10, 10), +) + +# shapes +square = Rect(x=20, y=70, width=40, height=40, fill=0x00DD00) +circle = Circle(50, 120, r=30, fill=0xDD00DD) +triangle = Triangle(50, 0, 100, 50, 0, 50, fill=0xDDDD00) +rectangle = Rect(x=80, y=80, width=100, height=50, fill=0x0000DD) + +triangle.x = 80 +triangle.y = 70 + +# add everything to their page groups +page_1_group.append(square) +page_1_group.append(page_1_lbl) +page_2_group.append(page_2_lbl) +page_2_group.append(circle) +page_3_group.append(page_3_lbl) +page_3_group.append(triangle) +page_4_group.append(page_4_lbl) +page_4_group.append(rectangle) + +# add the pages to the layout, supply your own page names +test_page_layout.add_content(page_1_group, "One") +test_page_layout.add_content(page_2_group, "Two") +test_page_layout.add_content(page_3_group, "Thr") +test_page_layout.add_content(page_4_group, "For") + +# add it to the group that is showing on the display +main_group.append(test_page_layout) + + +# add something new after the TabLayout was already created +another_text = Label( + terminalio.FONT, + text="And another thing!", + scale=2, + color=0x00FF00, + anchor_point=(0, 0), + anchored_position=(100, 100), +) +test_page_layout.showing_page_content.append(another_text) + +while True: + touch = ts.touch_point + if touch: + test_page_layout.handle_touch_events(touch) From 20a64dfcf5ca3b9c14684c9f380cb9ac34c711d2 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 6 May 2022 21:07:08 -0500 Subject: [PATCH 051/132] use showing instead of active throughout API --- .../layouts/tab_layout.py | 26 +++++++++---------- .../displayio_layout_tab_layout_simpletest.py | 6 ++--- .../displayio_layout_tab_layout_touchtest.py | 6 ++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index 61c7d76..ffcea7b 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -50,14 +50,14 @@ class TabLayout(displayio.Group): :param Optional[Union[BuiltinFont, BDF, PCF]] custom_font: A pre-loaded font object to use for the tab labels :param str inactive_tab_spritesheet: Filepath of the spritesheet to show for inactive tabs. - :param str active_tab_spritesheet: Filepath of the spritesheet to show for the active tab. - :param Optional[int, tuple[int, int, int]] active_tab_text_color: Hex or tuple color to use + :param str showing_tab_spritesheet: Filepath of the spritesheet to show for the active tab. + :param Optional[int, tuple[int, int, int]] showing_tab_text_color: Hex or tuple color to use for the active tab label :param Optional[int, tuple[int, int, int]] inactive_tab_text_color: Hex or tuple color to use for inactive tab labels :param Optional[Union[int, tuple[int, int]]] inactive_tab_transparent_indexes: single index or tuple of multiple indexes to be made transparent in the inactive tab sprite palette. - :param Optional[Union[int, tuple[int, int]]] active_tab_transparent_indexes: single index + :param Optional[Union[int, tuple[int, int]]] showing_tab_transparent_indexes: single index or tuple of multiple indexes to be made transparent in the active tab sprite palette. :param int tab_count: How many tabs to draw in the layout. Positive whole numbers are valid. """ @@ -72,11 +72,11 @@ def __init__( tab_text_scale: int = 1, custom_font: Optional[Union[BuiltinFont, BDF, PCF]] = terminalio.FONT, inactive_tab_spritesheet: Optional[str] = None, - active_tab_spritesheet: Optional[str] = None, - active_tab_text_color: Optional[Union[int, Tuple[int, int, int]]] = 0x999999, + showing_tab_spritesheet: Optional[str] = None, + showing_tab_text_color: Optional[Union[int, Tuple[int, int, int]]] = 0x999999, inactive_tab_text_color: Optional[Union[int, Tuple[int, int, int]]] = 0xFFFFF, inactive_tab_transparent_indexes: Optional[Union[int, Tuple[int, int]]] = None, - active_tab_transparent_indexes: Optional[Union[int, Tuple[int, int]]] = None, + showing_tab_transparent_indexes: Optional[Union[int, Tuple[int, int]]] = None, tab_count: int = None, ): @@ -88,7 +88,7 @@ def __init__( display = board.DISPLAY if inactive_tab_spritesheet is None: raise AttributeError("Must pass active_tab_spritesheet") - if active_tab_spritesheet is None: + if showing_tab_spritesheet is None: raise AttributeError("Must pass inactive_tab_spritesheet") if tab_count is None: raise AttributeError("Must pass tab_count") @@ -96,16 +96,16 @@ def __init__( super().__init__(x=x, y=y) self.tab_count = tab_count self._active_bmp, self._active_palette = adafruit_imageload.load( - active_tab_spritesheet + showing_tab_spritesheet ) self._inactive_bmp, self._inactive_palette = adafruit_imageload.load( inactive_tab_spritesheet ) - if isinstance(active_tab_transparent_indexes, int): - self._active_palette.make_transparent(active_tab_transparent_indexes) - elif isinstance(active_tab_transparent_indexes, tuple): - for index in active_tab_transparent_indexes: + if isinstance(showing_tab_transparent_indexes, int): + self._active_palette.make_transparent(showing_tab_transparent_indexes) + elif isinstance(showing_tab_transparent_indexes, tuple): + for index in showing_tab_transparent_indexes: self._active_palette.make_transparent(index) else: raise AttributeError("active_tab_transparent_indexes must be int or tuple") @@ -122,7 +122,7 @@ def __init__( self.tab_height = self._active_bmp.height self.display = display - self.active_tab_text_color = active_tab_text_color + self.active_tab_text_color = showing_tab_text_color self.inactive_tab_text_color = inactive_tab_text_color self.custom_font = custom_font self.tab_text_scale = tab_text_scale diff --git a/examples/displayio_layout_tab_layout_simpletest.py b/examples/displayio_layout_tab_layout_simpletest.py index 6759f5e..20ad427 100644 --- a/examples/displayio_layout_tab_layout_simpletest.py +++ b/examples/displayio_layout_tab_layout_simpletest.py @@ -33,11 +33,11 @@ tab_text_scale=2, custom_font=font, inactive_tab_spritesheet="bmps/inactive_tab_sprite.bmp", - active_tab_spritesheet="bmps/active_tab_sprite.bmp", - active_tab_text_color=0x00AA59, + showing_tab_spritesheet="bmps/active_tab_sprite.bmp", + showing_tab_text_color=0x00AA59, inactive_tab_text_color=0xEEEEEE, inactive_tab_transparent_indexes=(0, 1), - active_tab_transparent_indexes=(0, 1), + showing_tab_transparent_indexes=(0, 1), tab_count=4, ) diff --git a/examples/displayio_layout_tab_layout_touchtest.py b/examples/displayio_layout_tab_layout_touchtest.py index d8cd5bf..47c5cbd 100644 --- a/examples/displayio_layout_tab_layout_touchtest.py +++ b/examples/displayio_layout_tab_layout_touchtest.py @@ -46,11 +46,11 @@ tab_text_scale=2, custom_font=font, inactive_tab_spritesheet="bmps/inactive_tab_sprite.bmp", - active_tab_spritesheet="bmps/active_tab_sprite.bmp", - active_tab_text_color=0x00AA59, + showing_tab_spritesheet="bmps/active_tab_sprite.bmp", + showing_tab_text_color=0x00AA59, inactive_tab_text_color=0xEEEEEE, inactive_tab_transparent_indexes=(0, 1), - active_tab_transparent_indexes=(0, 1), + showing_tab_transparent_indexes=(0, 1), tab_count=4, ) From adca2d7958807aa55f69ee53b5348a117d6b4284 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 9 May 2022 18:36:45 -0500 Subject: [PATCH 052/132] docs warning and error message for cp version --- adafruit_displayio_layout/layouts/tab_layout.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index ffcea7b..e3ee2ca 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -42,6 +42,9 @@ class TabLayout(displayio.Group): """ A layout that organizes children into a grid table structure. + .. warning:: + Requires CircuitPython version 7.3.0-beta.2 or newer + :param int x: x location the layout should be placed. Pixel coordinates. :param int y: y location the layout should be placed. Pixel coordinates. :param displayio.Display display: The Display object to show the tab layout on. @@ -167,7 +170,15 @@ def _draw_tabs(self): _new_tab_group.append(_tab_label) if i == self.page_layout.showing_page_index: - _tab_tilegrid.bitmap = self._active_bmp + try: + _tab_tilegrid.bitmap = self._active_bmp + except AttributeError as e: + print(e) + raise ( + AttributeError( + "TabLayout requires CircuitPython version 7.3.0-beta.2 or newer." + ) + ) from e _tab_tilegrid.pixel_shader = self._active_palette _tab_label.color = self.active_tab_text_color self.tab_dict[i] = _new_tab_group From 206bff6f9ae3ccbcb48830ea119bae21faa6e7d0 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 12:47:03 +0100 Subject: [PATCH 053/132] Taken out 4 of 5 examples According suggestions of @FoamyGuy, I took out 4 out of the 5 examples I created. I also took out the /images/bgimg4.bmp. This all for the sake of being able to publish a PR in a next step. --- .gitignore | 1 + examples/bmps/active_tab_sprite.bmp | Bin 0 -> 1730 bytes examples/bmps/active_tab_sprite.bmp.license | 2 + examples/bmps/inactive_tab_sprite.bmp | Bin 0 -> 1738 bytes examples/bmps/inactive_tab_sprite.bmp.license | 2 + ...layout_hotplug_ext_rtc_temp_sensor_test.py | 513 ++++++++++++++++++ .../images/BGimage4.license | 3 + examples/secrets.py | 14 + 8 files changed, 535 insertions(+) create mode 100644 examples/bmps/active_tab_sprite.bmp create mode 100644 examples/bmps/active_tab_sprite.bmp.license create mode 100644 examples/bmps/inactive_tab_sprite.bmp create mode 100644 examples/bmps/inactive_tab_sprite.bmp.license create mode 100644 examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py create mode 100644 examples/hotplug_sensor_examples/images/BGimage4.license create mode 100644 examples/secrets.py diff --git a/.gitignore b/.gitignore index 544ec4a..5247efd 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ _build .idea .vscode *~ +examples/hotplug_sensor_examples/images/BGimage4.bmp diff --git a/examples/bmps/active_tab_sprite.bmp b/examples/bmps/active_tab_sprite.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d97d1db459fca77099770dbe32072eeca6e7a2fd GIT binary patch literal 1730 zcmZ?rJ;cTU28V!T4G`M^u>lY>GOz$iAOOlM>p?IdkPE^L4F6#W%yV)NDh4x1Aehk9 z{s)@*pAl#-5CrABFa#AkGX#}7G6Xl+Fod*PFoaFjVF;hC!VtNNfgxgv7(?tzNrs9= z5e%yqDd7ZKK((XtIDlY>GOz$iAOOlM>p`#pkPE^L4F6#W%yV)NDh4x1Aehk9 z{s)@*pYcC~zrR0&e}ErDK&&@IP`(R8P@ywJP^lwBaDxp)NUH@y*i;>c@YyO1k*gRO zB9@3T#IBTNs8|%iaORK_PM~v!fw25xoZ6MZ`UhH`QvXq?{|&AEPoeuLj{i~nm2d%~ z^3PBYzazMOucYJyDnE|mmX86-|2c_Ue$IIY2ACveI4faQ747GYPQeg|Yc&;d8F%lCq<2U>7u88!u3XTZjT3^=nh1YL#e>@!g9 fU 999: + cnt = 0 + # change page by next page function. It will loop by default + time.sleep(2) + test_page_layout.next_page() + except KeyboardInterrupt as exc: + raise KeyboardInterrupt("Keyboard interrupt...exiting...") from exc + # raise SystemExit + + +if __name__ == "__main__": + + main() diff --git a/examples/hotplug_sensor_examples/images/BGimage4.license b/examples/hotplug_sensor_examples/images/BGimage4.license new file mode 100644 index 0000000..0d48d75 --- /dev/null +++ b/examples/hotplug_sensor_examples/images/BGimage4.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2022 PaulskPt +# +# SPDX-License-Identifier: MIT diff --git a/examples/secrets.py b/examples/secrets.py new file mode 100644 index 0000000..e05bd25 --- /dev/null +++ b/examples/secrets.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2022 PaulskPt +# +# SPDX-License-Identifier: MIT +# +# This file is where you keep secret settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +secrets = { + "ssid": "here your WiFi SSID", + "password": "here your WiFi password", + "aio_username": "here your aio username", + "aio_key": "here your aio key", + "timezone": "Europe/Lisbon", # http://worldtimeapi.org/timezones +} From 977c6fa62bd395cf4124d99540cd21120033b82d Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 14:21:24 +0100 Subject: [PATCH 054/132] mod example --- ..._layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index d99d5ab..f4c3ea1 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -109,12 +109,12 @@ display=board.DISPLAY, tab_text_scale=2, custom_font=font, - inactive_tab_spritesheet="lib/adafruit_displayio_layout/examples/bmps/inactive_tab_sprite.bmp", - showing_tab_spritesheet="lib/adafruit_displayio_layout/examples/bmps/active_tab_sprite.bmp", - active_tab_text_color=0x00AA59, + inactive_tab_spritesheet="bmps/inactive_tab_sprite.bmp", + showing_tab_spritesheet="bmps/active_tab_sprite.bmp", + showing_tab_text_color=0x00AA59, inactive_tab_text_color=0xEEEEEE, inactive_tab_transparent_indexes=(0, 1), - active_tab_transparent_indexes=(0, 1), + showing_tab_transparent_indexes=(0, 1), tab_count=4, ) From 447425758b4fb7678cf77e26bb6d5f4a64ecb983 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 15:10:24 +0100 Subject: [PATCH 055/132] mod in test mod dict pages to use different Tab texts when using a PyPortal model Titano --- ...yio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index f4c3ea1..35f1166 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -212,7 +212,10 @@ pge4_group.append(pge4_lbl3) pge4_group.append(rectangle) -pages = {0: "One", 1: "Two", 2: "Thr", 3: "For"} +if board.board_id == "pyportal_titano": + pages = {0: "Dum", 1: "One", 2: "Two", 3: "Three", 4: "Four"} +else: + pages = {0: "Dum", 1: "One", 2: "Two", 3: "Thr", 3: "For"} # add the pages to the layout, supply your own page names test_page_layout.add_content(pge1_group, pages[0]) From 3beeb82933c631efd4407fab2d550e832b7d3882 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 15:26:19 +0100 Subject: [PATCH 056/132] mod example Index to dictionary pages has to start at 1, not at 0 (which is a 'dummy) --- ..._layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index 35f1166..4aae37c 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -218,10 +218,10 @@ pages = {0: "Dum", 1: "One", 2: "Two", 3: "Thr", 3: "For"} # add the pages to the layout, supply your own page names -test_page_layout.add_content(pge1_group, pages[0]) -test_page_layout.add_content(pge2_group, pages[1]) -test_page_layout.add_content(pge3_group, pages[2]) -test_page_layout.add_content(pge4_group, pages[3]) +test_page_layout.add_content(pge1_group, pages[1]) +test_page_layout.add_content(pge2_group, pages[2]) +test_page_layout.add_content(pge3_group, pages[3]) +test_page_layout.add_content(pge4_group, pages[4]) # test_page_layout.add_content(displayio.Group(), "page_5") From d354d357c410a37cc43098313c5e5c5e5c22b1c2 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 18:36:04 +0100 Subject: [PATCH 057/132] example default datetime setting modified idem --- ...playio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index 4aae37c..40be9e0 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -20,7 +20,7 @@ from adafruit_displayio_layout.layouts.tab_layout import TabLayout # Adjust here the date and time that you want the RTC to be set at start: -default_dt = time.struct_time((2022, 5, 2, 2, 48, 0, 0, -1, -1)) +default_dt = time.struct_time((2022, 5, 12, 18, 34, 0, 3, -1, -1)) my_debug = True From 8d1c916ef4b258cd5f63e0228d0f4f823e9f90be Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 18:48:46 +0100 Subject: [PATCH 058/132] removed images subfolder idem --- examples/hotplug_sensor_examples/images/BGimage4.license | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 examples/hotplug_sensor_examples/images/BGimage4.license diff --git a/examples/hotplug_sensor_examples/images/BGimage4.license b/examples/hotplug_sensor_examples/images/BGimage4.license deleted file mode 100644 index 0d48d75..0000000 --- a/examples/hotplug_sensor_examples/images/BGimage4.license +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: 2022 PaulskPt -# -# SPDX-License-Identifier: MIT From ace51c787388d52c65b5b324dd32d6e4b3efdc73 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Thu, 12 May 2022 20:19:15 +0100 Subject: [PATCH 059/132] editorial changes to the example idem --- ...layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index 40be9e0..76a771d 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -330,8 +330,9 @@ def connect_rtc(): """ Function gets a value from the external temperature sensor It only updates if the value has changed compared to the previous value - If no value obtained (for instance if the sensor is disconnected) - the function sets the page_4 label to a default text + A fixed text is set in pge4_lbl2.text. The variable temperature value is set in pge4_lbl3.text + If no value obtained (for instance if the sensor is disconnected), + the function sets the pge4_lbl to a default text and makes empty pge4_lbl2.text and pge4_lbl3.text """ @@ -449,8 +450,8 @@ def handle_dt(dt): a) if an rtc is present from the rtc; b) if using online NTP pool server then get the date and time from the function time.localtime This time.localtime has before been set with data from the NTP server. - In both cases the date and time will be set to the page3_lbl, lbl12 and lbl3 - If no (valid) date and time has been received then a default text will be shown on the page3_lbl + In both cases the date and time will be set to the pge3_lbl, pge3_lbl12 and pge3_lbl3 + If no (valid) date and time has been received then a default text will be shown on the pge3_lbl """ From 8b2bcd58702e670f88b6a89a911fcad529d902b2 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sat, 14 May 2022 00:07:23 +0100 Subject: [PATCH 060/132] mods to the example Mods necessary to eliminate global variables as much as possible. Deleted flags: rtc_present, t_sensor_present. Replaces them by tests like: 'if rtc is not None' --- ...layout_hotplug_ext_rtc_temp_sensor_test.py | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index 76a771d..e2acf5f 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -4,7 +4,7 @@ """ Make a PageLayout and illustrate all of it's features """ -# pylint: disable-all +# pylint: disable=global-statement import time import displayio import board @@ -64,7 +64,6 @@ lStart = True -rtc_present = None rtc = None o_secs = 0 # old seconds c_secs = 0 # current seconds @@ -74,7 +73,6 @@ sDT_old = "" -t_sensor_present = None tmp117 = None t0 = None t1 = None @@ -215,7 +213,7 @@ if board.board_id == "pyportal_titano": pages = {0: "Dum", 1: "One", 2: "Two", 3: "Three", 4: "Four"} else: - pages = {0: "Dum", 1: "One", 2: "Two", 3: "Thr", 3: "For"} + pages = {0: "Dum", 1: "One", 2: "Two", 3: "Thr", 4: "For"} # add the pages to the layout, supply your own page names test_page_layout.add_content(pge1_group, pages[1]) @@ -269,9 +267,9 @@ def connect_temp_sensor(): - global t_sensor_present, tmp117, t0, t1, t2 + global tmp117, t0, t1, t2 t = "temperature sensor found" - t_sensor_present = False + tmp117 = None try: @@ -280,9 +278,6 @@ def connect_temp_sensor(): pass if tmp117 is not None: - t_sensor_present = True - - if t_sensor_present: print(t) print("temperature sensor connected") t0 = "Temperature" @@ -299,15 +294,13 @@ def connect_temp_sensor(): """ If the external rtc has been disconnected, this function will try to reconnect (test if the external rtc is present by now) - If reconnected this function sets the global variable rtc_present - If failed to reconnect the function clears rtc_present """ def connect_rtc(): - global rtc_present, rtc, lStart + global rtc, lStart t = "RTC found" - rtc_present = False + rtc = None try: rtc = DS3231(i2c) # i2c addres 0x68 @@ -315,7 +308,6 @@ def connect_rtc(): pass if rtc is not None: - rtc_present = True print(t) print("RTC connected") if lStart: @@ -332,15 +324,17 @@ def connect_rtc(): It only updates if the value has changed compared to the previous value A fixed text is set in pge4_lbl2.text. The variable temperature value is set in pge4_lbl3.text If no value obtained (for instance if the sensor is disconnected), - the function sets the pge4_lbl to a default text and makes empty pge4_lbl2.text and pge4_lbl3.text + the function sets the pge4_lbl to a default text and makes empty + pge4_lbl2.text and pge4_lbl3.text """ def get_temp(): - global t_sensor_present, old_temp, tmp117, pge4_lbl, pge4_lbl2, pge4_lbl3, temp_in_REPL + global old_temp, tmp117, temp_in_REPL + showing_page_idx = test_page_layout.showing_page_index RetVal = False - if t_sensor_present: + if tmp117 is not None: try: temp = tmp117.temperature t = "{:5.2f} ".format(temp) + t1 @@ -367,7 +361,6 @@ def get_temp(): except OSError: print("Temperature sensor has disconnected") t = "" - t_sensor_present = False tmp117 = None pge4_lbl.text = pge4_lbl_dflt # clean the line (eventually: t2) pge4_lbl2.text = "" @@ -391,7 +384,7 @@ def get_temp(): def handle_dt(dt): - global pge3_lbl, pge3_lbl2, pge3_lbl3, o_secs, c_secs, dt_refresh, sDT_old + global o_secs, c_secs, dt_refresh, sDT_old RetVal = False s = "Date/time: " sYY = str(dt[yy]) @@ -456,18 +449,17 @@ def handle_dt(dt): def get_dt(): - global rtc_present, pge3_lbl, pge3_lbl2, pge3_lbl3 + dt = None RetVal = False - if rtc_present: + if rtc is not None: try: dt = rtc.datetime except OSError as exc: if my_debug: print("Error number: ", exc.args[0]) if exc.args[0] == 5: # Input/output error - rtc_present = False print("get_dt(): OSError occurred. RTC probably is disconnected") pge3_lbl.text = pge3_lbl_dflt return RetVal @@ -491,12 +483,12 @@ def main(): try: print("Loop nr: {:03d}".format(cnt)) - if rtc_present: + if rtc is not None: get_dt() else: connect_rtc() - if t_sensor_present: + if tmp117 is not None: get_temp() else: connect_temp_sensor() From 262c9be712e25c9605da605d0854d742d7d79847 Mon Sep 17 00:00:00 2001 From: Randall Bohn Date: Sat, 14 May 2022 09:46:26 -0600 Subject: [PATCH 061/132] align init() error messages Match error messages to the required init() parameters --- adafruit_displayio_layout/layouts/tab_layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index e3ee2ca..2d05586 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -90,9 +90,9 @@ def __init__( if hasattr(board, "DISPLAY"): display = board.DISPLAY if inactive_tab_spritesheet is None: - raise AttributeError("Must pass active_tab_spritesheet") - if showing_tab_spritesheet is None: raise AttributeError("Must pass inactive_tab_spritesheet") + if showing_tab_spritesheet is None: + raise AttributeError("Must pass showing_tab_spritesheet") if tab_count is None: raise AttributeError("Must pass tab_count") From 2e240323ff49008bfe9250fe66a19566837602fb Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sat, 14 May 2022 20:22:15 +0100 Subject: [PATCH 062/132] example updated Now all globals used before are contained in an added gVars class. --- ...layout_hotplug_ext_rtc_temp_sensor_test.py | 349 ++++++++++++------ 1 file changed, 242 insertions(+), 107 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index e2acf5f..97dd031 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -4,7 +4,7 @@ """ Make a PageLayout and illustrate all of it's features """ -# pylint: disable=global-statement + import time import displayio import board @@ -15,14 +15,138 @@ from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle from adafruit_display_shapes.triangle import Triangle - -# from adafruit_bitmap_font import bitmap_font from adafruit_displayio_layout.layouts.tab_layout import TabLayout -# Adjust here the date and time that you want the RTC to be set at start: -default_dt = time.struct_time((2022, 5, 12, 18, 34, 0, 3, -1, -1)) +# +-------------------------------------------------------+ +# | Definition for variables in the past defined as global| +# +-------------------------------------------------------+ +# The gVars class is created +# to elminate the need for global variables. + + +class gVars: + def __init__(self): + + self.gVarsDict = { + 0: "my_debug", + 1: "rtc", + 2: "temp_sensor", + 3: "lStart", + 4: "o_secs", + 5: "c_secs", + 6: "dt_refresh", + 7: "sDT_old", + 8: "t0", + 9: "t1", + 10: "t2", + 11: "default_dt", + 12: "pge3_lbl_dflt", + 13: "pge4_lbl_dflt", + 14: "online_time_present", + 15: "temp_in_REPL", + 16: "old_temp", + 17: "use_ntp", + 18: "use_txt_in_month", + 19: "use_usa_notation", + 20: "content_sensor_idx", + } + + self.gVars_rDict = { + "my_debug": 0, + "rtc": 1, + "temp_sensor": 2, + "lStart": 3, + "o_secs": 4, + "c_secs": 5, + "dt_refresh": 6, + "sDT_old": 7, + "t0": 8, + "t1": 9, + "t2": 10, + "default_dt": 11, + "pge3_lbl_dflt": 12, + "pge4_lbl_dflt": 13, + "online_time_present": 14, + "temp_in_REPL": 15, + "old_temp": 16, + "use_ntp": 17, + "use_txt_in_month": 18, + "use_usa_notation": 19, + "content_sensor_idx": 20, + } + + self.g_vars = {} + + # self.clean() + + def write(self, s, value): + if isinstance(s, str): + if s in self.gVars_rDict: + n = self.gVars_rDict[s] + # print("myVars.write() \'{:" ">20s}\'found in self.gVars_rDict, + # key: {}".format(s, n)) + self.g_vars[n] = value + else: + raise KeyError( + "variable '{:" ">20s}' not found in self.gVars_rDict".format(s) + ) + else: + raise TypeError( + "myVars.write(): param s expected str, {} received".format(type(s)) + ) + + def read(self, s): + RetVal = None + if isinstance(s, str): + if s in self.gVars_rDict: + n = self.gVars_rDict[s] + if n in self.g_vars: + RetVal = self.g_vars[n] + return RetVal + + def clean(self): + self.g_vars = { + 0: None, + 1: None, + 2: None, + 3: None, + 4: None, + 5: None, + 6: None, + 7: None, + 8: None, + 9: None, + 10: None, + 11: None, + 12: None, + 13: None, + 14: None, + 15: None, + 16: None, + 17: None, + 18: None, + 19: None, + 20: None, + } + + def list(self): + for i in range(0, len(self.g_vars) - 1): + print( + "self.g_vars['{:" + ">20s}'] = {}".format( + self.gVarsDict[i], self.g_vars[i] if i in self.g_vars else "None" + ) + ) + + +# ---------- End of class gVars ------------------------ + +myVars = gVars() # create an instance of the gVars class + +myVars.write("my_debug", False) -my_debug = True +# Adjust here the date and time that you want the RTC to be set at start: +myVars.write("default_dt", time.struct_time((2022, 5, 14, 19, 42, 0, 5, -1, -1))) months = { 0: "Dum", @@ -40,16 +164,11 @@ 12: "Dec", } -use_txt_in_month = True -use_usa_notation = True -use_ntp = False - i2c = board.I2C() -if my_debug: +if myVars.read("my_debug"): while not i2c.try_lock(): pass - try: while True: print( @@ -58,34 +177,38 @@ ) time.sleep(2) break - finally: # unlock the i2c bus when ctrl-c'ing out of the loop i2c.unlock() - -lStart = True -rtc = None -o_secs = 0 # old seconds -c_secs = 0 # current seconds - -# used to flag when more or less static elements in datetime stamp have to be refreshed -dt_refresh = True - -sDT_old = "" - -tmp117 = None -t0 = None -t1 = None -t2 = None +# -------------- Setting myVars elements ---------------------------------- +myVars.write("rtc", None) +myVars.write("temp_sensor", None) +myVars.write("lStart", True) +myVars.write("o_secs", 0) # old seconds +myVars.write("c_secs", 0) # current seconds +# dt_refresh is used to flag when more or less static elements +# in datetime stamp have to be refreshed +myVars.write("dt_refresh", True) +myVars.write("sDT_old", "") +myVars.write("t0", None) +myVars.write("t1", None) +myVars.write("t2", None) +# default_dt already set above +myVars.write("pge3_lbl_dflt", "The third page is fun!") +myVars.write("pge4_lbl_dflt", "The fourth page is where it's at") +myVars.write("online_time_present", False) +myVars.write("temp_in_REPL", False) +myVars.write("old_temp", 0.00) +myVars.write("use_txt_in_month", True) +myVars.write("use_usa_notation", True) +myVars.write("use_ntp", False) +myVars.write("content_sensor_idx", None) +# ------------------------------------------------------------------------- +if myVars.read("my_debug"): + # print list of all variables in myVars + myVars.list() # degs_sign = chr(186) # I preferred the real degrees sign which is: chr(176) - -content_sensor_idx = None -pge3_lbl_dflt = "The third page is fun!" -pge4_lbl_dflt = "The fourth page is where it's at" - -online_time_present = None - # ----------------------------------- # built-in display @@ -97,7 +220,7 @@ main_group = displayio.Group() display.show(main_group) -# font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") +# fon.gvars bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") font = terminalio.FONT # create the page layout @@ -147,7 +270,7 @@ pge3_lbl = Label( font=terminalio.FONT, scale=2, - text=pge3_lbl_dflt, # Will be "Date/time:" + text=myVars.read("pge3_lbl_dflt"), # Will be "Date/time:" anchor_point=(0, 0), anchored_position=(10, 10), ) @@ -168,7 +291,7 @@ pge4_lbl = Label( font=terminalio.FONT, scale=2, - text=pge4_lbl_dflt, + text=myVars.read("pge4_lbl_dflt"), anchor_point=(0, 0), anchored_position=(10, 10), ) @@ -254,9 +377,7 @@ anchored_position=(100, 100)) test_page_layout.showing_page_content.append(another_text) """ -print("starting loop") -old_temp = 0.00 """ If the temperature sensor has been disconnected, @@ -267,28 +388,31 @@ def connect_temp_sensor(): - global tmp117, t0, t1, t2 t = "temperature sensor found" - tmp117 = None + # myVars.write("temp_sensor",None) try: - tmp117 = adafruit_tmp117.TMP117(i2c) + myVars.write("temp_sensor", adafruit_tmp117.TMP117(i2c)) except ValueError: # ValueError occurs if the temperature sensor is not connected pass - if tmp117 is not None: + print( + "connect_temp_sensor(): type(temp_sensor) object = ", + type(myVars.read("temp_sensor")), + ) + if myVars.read("temp_sensor") is not None: print(t) print("temperature sensor connected") - t0 = "Temperature" - t1 = " C" - t2 = 27 * "_" + myVars.write("t0", "Temperature") + myVars.write("t1", " C") + myVars.write("t2", 27 * "_") else: print("no " + t) print("failed to connect temperature sensor") - t0 = None - t1 = None - t2 = None + myVars.write("t0", None) + myVars.write("t1", None) + myVars.write("t2", None) """ @@ -298,27 +422,28 @@ def connect_temp_sensor(): def connect_rtc(): - global rtc, lStart t = "RTC found" - rtc = None + # myVars.write("rtc",None) + try: - rtc = DS3231(i2c) # i2c addres 0x68 + myVars.write("rtc", DS3231(i2c)) # i2c addres 0x68 + # myVars.write("rtc",rtc) except ValueError: pass - if rtc is not None: + print("connect_rtc() type rtc object = ", type(myVars.read("rtc"))) + if myVars.read("rtc") is not None: print(t) print("RTC connected") - if lStart: - lStart = False - rtc.datetime = default_dt + if myVars.read("lStart"): + myVars.write("lStart", False) + myVars.read("rtc").datetime = myVars.read("default_dt") else: print("no " + t) print("Failed to connect RTC") -temp_in_REPL = False """ Function gets a value from the external temperature sensor It only updates if the value has changed compared to the previous value @@ -330,45 +455,54 @@ def connect_rtc(): def get_temp(): - global old_temp, tmp117, temp_in_REPL - showing_page_idx = test_page_layout.showing_page_index RetVal = False - if tmp117 is not None: + if myVars.read("temp_sensor") is not None: try: - temp = tmp117.temperature - t = "{:5.2f} ".format(temp) + t1 - if my_debug and temp is not None and not temp_in_REPL: - temp_in_REPL = True - print("get_temp(): {} {}".format(t0, t)) + temp = myVars.read("temp_sensor").temperature + t = "{:5.2f} ".format(temp) + myVars.read("t1") + if ( + myVars.read("my_debug") + and temp is not None + and not myVars.read("temp_in_REPL") + ): + myVars.write("temp_in_REPL", True) + print("get_temp(): {} {}".format(myVars.read("t0"), t)) if showing_page_idx == 3: # show temperature on most right Tab page if temp is not None: - if ( - temp != old_temp + if temp != myVars.read( + "old_temp" ): # Only update if there is a change in temperature - old_temp = temp - t = "{:5.2f} ".format(temp) + t1 + myVars.write("old_temp", temp) + t = "{:5.2f} ".format(temp) + myVars.read("t1") pge4_lbl.text = "" - pge4_lbl2.text = t0 + pge4_lbl2.text = myVars.read("t0") pge4_lbl3.text = t # if not my_debug: - # print("pge4_lbl.text = {}".format(pge4_lbl.text)) + # print("pge4_lbl.tex.gvars {}".format(pge4_lbl.text)) # time.sleep(2) RetVal = True else: t = "" - pge4_lbl.text = pge4_lbl_dflt + pge4_lbl.text = myVars.read("pge4_lbl_dflt") except OSError: print("Temperature sensor has disconnected") t = "" - tmp117 = None - pge4_lbl.text = pge4_lbl_dflt # clean the line (eventually: t2) + myVars.write("temp_sensor", None) + pge4_lbl.text = myVars.read( + "pge4_lbl_dflt" + ) # clean the line (eventually: t2) pge4_lbl2.text = "" pge4_lbl3.text = "" return RetVal +""" + Function called by get_dt() + Created to repair pylint error R0912: Too many branches (13/12) +""" + yy = 0 mo = 1 dd = 2 @@ -377,20 +511,14 @@ def get_temp(): ss = 5 -""" - Function called by get_dt() - Created to repair pylint error R0912: Too many branches (13/12) -""" - - def handle_dt(dt): - global o_secs, c_secs, dt_refresh, sDT_old + RetVal = False s = "Date/time: " sYY = str(dt[yy]) sMO = ( months[dt[mo]] - if use_txt_in_month + if myVars.read("use_txt_in_month") else "0" + str(dt[mo]) if dt[mo] < 10 else str(dt[mo]) @@ -401,33 +529,34 @@ def handle_dt(dt): for _ in range(dd, ss + 1): dt_dict[_] = "0" + str(dt[_]) if dt[_] < 10 else str(dt[_]) - if my_debug: + if myVars.read("my_debug"): print("dt_dict = ", dt_dict) - c_secs = dt_dict[ss] + myVars.write("c_secs", dt_dict[ss]) sDT = ( sMO + "-" + dt_dict[dd] + "-" + sYY - if use_usa_notation + if myVars.read("use_usa_notation") else sYY + "-" + sMO + "-" + dt_dict[dd] ) - - if sDT_old != sDT: - sDT_old = sDT - dt_refresh = True # The date has changed, set the refresh flag + if myVars.read("my_debug"): + print("handle_dt(): sDT_old = {}, sDT = {}".format(myVars.read("sDT_old"), sDT)) + if myVars.read("sDT_old") != sDT: + myVars.write("sDT_old", sDT) + myVars.write("dt_refresh", True) # The date has changed, set the refresh flag sDT2 = dt_dict[hh] + ":" + dt_dict[mm] + ":" + dt_dict[ss] - if dt_refresh: # only refresh when needed - dt_refresh = False + if myVars.read("dt_refresh"): # only refresh when needed + myVars.write("dt_refresh", False) pge3_lbl.text = s pge3_lbl2.text = sDT - if c_secs != o_secs: - o_secs = c_secs + if myVars.read("c_secs") != myVars.read("o_secs"): + myVars.write("o_secs", myVars.read("c_secs")) sDT3 = s + "{} {}".format(sDT, sDT2) print(sDT3) pge3_lbl3.text = sDT2 - if my_debug: + if myVars.read("my_debug"): print("pge3_lbl.text = {}".format(pge3_lbl.text)) print("pge3_lbl2.text = {}".format(pge3_lbl2.text)) print("pge3_lbl3.text = {}".format(pge3_lbl3.text)) @@ -449,50 +578,56 @@ def handle_dt(dt): def get_dt(): - dt = None RetVal = False - if rtc is not None: + if myVars.read("rtc") is not None: try: - dt = rtc.datetime + dt = myVars.read("rtc").datetime except OSError as exc: - if my_debug: + if myVars.read("my_debug"): print("Error number: ", exc.args[0]) if exc.args[0] == 5: # Input/output error print("get_dt(): OSError occurred. RTC probably is disconnected") - pge3_lbl.text = pge3_lbl_dflt + pge3_lbl.text = myVars.read("pge3_lbl_dflt") + myVars.write("sDT_old", "") + pge3_lbl2.text = "" + pge3_lbl3.text = "" return RetVal raise # Handle other errors - elif online_time_present or use_ntp: + elif myVars.read("online_time_present") or myVars.read("use_ntp"): dt = time.localtime() + if myVars.read("my_debug"): + print("get_dt(): dt = ", dt) if dt is not None: RetVal = handle_dt(dt) else: - pge3_lbl.text = pge3_lbl_dflt + pge3_lbl.text = myVars.read("pge3_lbl_dflt") pge3_lbl2.text = "" pge3_lbl3.text = "" return RetVal +print("starting loop") + + def main(): cnt = 0 while True: try: print("Loop nr: {:03d}".format(cnt)) - - if rtc is not None: + # print("main(): type(rtc) object = ", type(myVars.read("rtc"))) + if myVars.read("rtc") is not None: get_dt() else: connect_rtc() - - if tmp117 is not None: + # print("main(): type(temp_sensor) object = ", type(myVars.read("temp_sensor"))) + if myVars.read("temp_sensor") is not None: get_temp() else: connect_temp_sensor() - cnt += 1 if cnt > 999: cnt = 0 From 3ecb29387058010352d296a7938fc99475559ac0 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sun, 15 May 2022 15:25:16 +0100 Subject: [PATCH 063/132] added example Example using datetime from NTP server, Touch interface. Using gVars class to set/get globally used variables. --- ...or_datetime_fm_NTP_touch_and_gVars_test.py | 997 ++++++++++++++++++ 1 file changed, 997 insertions(+) create mode 100644 examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py diff --git a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py new file mode 100644 index 0000000..d3c6789 --- /dev/null +++ b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py @@ -0,0 +1,997 @@ +# SPDX-FileCopyrightText: 2022 PaulskPt +# +# SPDX-License-Identifier: MIT +""" +Notes by @PaulskPt: tested on an Adafruit PyPortal Titano +(Product ID 4444. See: https://www.adafruit.com/product/4444) +This script can make use of an I2C Realtime Clock type DS3231 +When the flag 'use_ntp' is set, the DS3231 will not be used, +instead the NTP class from adafruit_ntp.py will be used. +""" + +import time + +# import gc +import board +import busio +import displayio +import terminalio +import adafruit_tmp117 +from adafruit_ds3231 import DS3231 +from digitalio import DigitalInOut +import neopixel +import adafruit_touchscreen +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_ntp import NTP +from adafruit_pyportal import PyPortal +from adafruit_display_text.bitmap_label import Label +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.triangle import Triangle +from adafruit_bitmap_font import bitmap_font +from adafruit_displayio_layout.layouts.tab_layout import TabLayout + +# +-------------------------------------------------------+ +# | Definition for variables in the past defined as global| +# +-------------------------------------------------------+ +# The gVars class is created +# to elminate the need for global variables. + + +class gVars: + def __init__(self): + + self.gVarsDict = { + 0: "my_debug", + 1: "rtc", + 2: "temp_sensor", + 3: "lStart", + 4: "o_secs", + 5: "c_secs", + 6: "dt_refresh", + 7: "sDT_old", + 8: "t0", + 9: "t1", + 10: "t2", + 11: "default_dt", + 12: "pge3_lbl_dflt", + 13: "pge4_lbl_dflt", + 14: "online_time_present", + 15: "temp_in_REPL", + 16: "old_temp", + 17: "use_ntp", + 18: "use_txt_in_month", + 19: "use_usa_notation", + 20: "content_sensor_idx", + 21: "ntp_refresh", + 22: "nHH_old", + 23: "next_NTP_sync", + 24: "s_cnt", + 25: "five_min_cnt", + 26: "next_NTP_sync_t1", + 27: "next_NTP_sync_t3", + } + + self.gVars_rDict = { + "my_debug": 0, + "rtc": 1, + "temp_sensor": 2, + "lStart": 3, + "o_secs": 4, + "c_secs": 5, + "dt_refresh": 6, + "sDT_old": 7, + "t0": 8, + "t1": 9, + "t2": 10, + "default_dt": 11, + "pge3_lbl_dflt": 12, + "pge4_lbl_dflt": 13, + "online_time_present": 14, + "temp_in_REPL": 15, + "old_temp": 16, + "use_ntp": 17, + "use_txt_in_month": 18, + "use_usa_notation": 19, + "content_sensor_idx": 20, + "ntp_refresh": 21, + "nHH_old": 22, + "next_NTP_sync": 23, + "s_cnt": 24, + "five_min_cnt": 25, + "next_NTP_sync_t1": 26, + "next_NTP_sync_t3": 27, + } + + self.g_vars = {} + + # self.clean() + + def write(self, s, value): + if isinstance(s, str): + if s in self.gVars_rDict: + n = self.gVars_rDict[s] + # print("myVars.write() \'{:" ">20s}\'found in self.gVars_rDict, + # key: {}".format(s, n)) + self.g_vars[n] = value + else: + raise KeyError( + "variable '{:" ">20s}' not found in self.gVars_rDict".format(s) + ) + else: + raise TypeError( + "myVars.write(): param s expected str, {} received".format(type(s)) + ) + + def read(self, s): + RetVal = None + if isinstance(s, str): + if s in self.gVars_rDict: + n = self.gVars_rDict[s] + if n in self.g_vars: + RetVal = self.g_vars[n] + return RetVal + + def clean(self): + self.g_vars = { + 0: None, + 1: None, + 2: None, + 3: None, + 4: None, + 5: None, + 6: None, + 7: None, + 8: None, + 9: None, + 10: None, + 11: None, + 12: None, + 13: None, + 14: None, + 15: None, + 16: None, + 17: None, + 18: None, + 19: None, + 20: None, + 21: None, + 22: None, + 23: None, + 24: None, + 25: None, + 26: None, + 27: None, + } + + def list(self): + for i in range(0, len(self.g_vars) - 1): + print( + "self.g_vars['{:" + ">20s}'] = {}".format( + self.gVarsDict[i], self.g_vars[i] if i in self.g_vars else "None" + ) + ) + + +# ---------- End of class gVars ------------------------ + +myVars = gVars() # create an instance of the gVars class + +myVars.write("my_debug", False) + +# Adjust here the date and time that you want the RTC to be set at start: +myVars.write("default_dt", time.struct_time((2022, 5, 14, 11, 42, 0, 5, -1, -1))) + +# start_time = time.monotonic() + +# -------------- Setting myVars elements ---------------------------------- +myVars.write("rtc", None) +myVars.write("temp_sensor", None) +myVars.write("lStart", True) +myVars.write("o_secs", 0) # old seconds +myVars.write("c_secs", 0) # current seconds +# dt_refresh is used to flag when more or less static elements +# in datetime stamp have to be refreshed +myVars.write("dt_refresh", True) +myVars.write("sDT_old", "") +myVars.write("t0", None) +myVars.write("t1", None) +myVars.write("t2", None) +# default_dt already set above +myVars.write("pge3_lbl_dflt", "The third page is fun!") +myVars.write("pge4_lbl_dflt", "The fourth page is where it's at") +myVars.write("online_time_present", False) +myVars.write("temp_in_REPL", False) +myVars.write("old_temp", 0.00) +myVars.write("use_txt_in_month", True) +myVars.write("use_usa_notation", True) +myVars.write("use_ntp", True) +myVars.write("content_sensor_idx", None) +myVars.write("ntp_refresh", True) +myVars.write("next_NTP_sync", 0) +myVars.write("s_cnt", 0) +myVars.write("five_min_cnt", 0) +myVars.write("next_NTP_sync_t1", "Next NTP sync in ") +myVars.write("next_NTP_sync_t3", " (mm:ss)") +# nHH_old is used to check if the hour has changed. +# If so we have to re-sync from NTP server +# (if not using an external RTC) +myVars.write("nHH_old", -1) + +if myVars.read("my_debug"): + # print list of all variables in myVars + myVars.list() +# ------------------------------------------------------------------------- +# degs_sign = chr(186) # I preferred the real degrees sign which is: chr(176) + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) + +# ---------- Text Boxes ------------- # +# Set the font and preload letters +font_arial = bitmap_font.load_font( + "/fonts/Arial-16.bdf" +) # was: Helvetica-Bold-16.bdf") +# font.load_glyphs(b"abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()") +glyphs = b' "(),-.0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +font_arial.load_glyphs(glyphs) +font_arial.load_glyphs(("°",)) # a non-ascii character we need +# gc.collect() # ADDED by @PaulskPt -- to prevent MemoryError - memory allocation failed, +# allocating 6444 bytes + +# ------------- Screen Setup ------------- # +pyportal = None +timeout_cnt = 0 +while pyportal is None: + try: + pyportal = PyPortal( + esp=esp, external_spi=spi, debug=True + ) # esp=esp, external_spi=spi) # create a PyPortal object + if pyportal is not None: + break + except ValueError: # Occurred the error: "SCK in use". + # Also occurred the error "SPEAKER_ENABLE in use" + time.sleep(0.5) + timeout_cnt += 1 + if timeout_cnt > 10: + print("Timeout occurred while trying to create a PyPortal object") + raise + +months = { + 0: "Dum", + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", +} + +i2c = board.I2C() + +if myVars.read("use_ntp"): + print( + "\ntest_page_layout.showing_page_index test with I2C Temperature sensor and NTP \ +synchronized local time" + ) +else: + print("\nTabLayout test with I2C Temperature sensor and I2C Realtime clock") +print("Add your WiFi SSID, WiFi password and Timezone in file: secrets.h\n") + +if myVars.read("my_debug"): + while not i2c.try_lock(): + pass + + try: + while True: + print( + "I2C addresses found:", + [hex(device_address) for device_address in i2c.scan()], + ) + time.sleep(2) + break + + finally: # unlock the i2c bus when ctrl-c'ing out of the loop + i2c.unlock() + +# -------- Setting up SDCard --------------------- +# Is not needed to be done here: the SPI module is taking care of initializing the SD Card. +# See: https://andyfelong.com/2019/07/pyportal-access-the-micro-sd-card/#:~:text= \ +# It%20also%20has%20support%20for%20a%20micro%2DSD%20Card.&text=Software%20support%20 \ +# for%20PyPortal%20is, \ +# %2Din%20serial%2Dport%20terminal.77 +# +# NOTE: there is also the board.SD_CARD_DETECT pin (33)(but I don't know yet how to interface it) +#### + +# you'll need to pass in an io username and key +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +if myVars.read("my_debug"): + if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: + print("ESP32 found and in idle mode") + print("Firmware vers.", esp.firmware_version) + print("MAC addr:", [hex(i) for i in esp.MAC_address]) + + for ap in esp.scan_networks(): + print("\t%s\t\tRSSI: %d" % (str(ap["ssid"], "utf-8"), ap["rssi"])) + +# Get our username, key and desired timezone +location = secrets.get("timezone", None) + +print("\nConnecting to AP...") +while not esp.is_connected: + try: + esp.connect_AP(secrets["ssid"], secrets["password"]) + except RuntimeError as e: + print("could not connect to AP, retrying: ", e) + continue +print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi) +print("Please wait...") +if myVars.read("my_debug"): + print("My IP address is", esp.pretty_ip(esp.ip_address)) + print( + "IP lookup adafruit.com: %s" + % esp.pretty_ip(esp.get_host_by_name("adafruit.com")) + ) + print("Ping google.com: %d ms" % esp.ping("google.com")) + + +def refresh_from_NTP(): + # Fetch and set the microcontroller's current UTC time + # keep retrying until a valid time is returned + timeout_cnt2 = 0 + while not ntp.valid_time: + ntp.set_time(tz_offset) + if myVars.read("my_debug"): + print("Failed to obtain time, retrying in 5 seconds...") + timeout_cnt2 += 1 + time.sleep(5) + if timeout_cnt2 > 10: + print("Timeout while trying to get ntp datetime to set the internal rtc") + break + if myVars.read("my_debug"): + print("Value ntp.valid_time = ", ntp.valid_time) + if ntp.valid_time: + myVars.write("online_time_present", True) + myVars.write("ntp_refresh", False) + # Get the current time in seconds since Jan 1, 1970 and correct it for local timezone + # (defined in secrets.h) + ntp_current_time = time.time() + if myVars.read("my_debug"): + print("Seconds since Jan 1, 1970: {} seconds".format(ntp_current_time)) + # Convert the current time in seconds since Jan 1, 1970 to a struct_time + myVars.write("default_dt", time.localtime(ntp_current_time)) + if not myVars.read("my_debug"): + print( + "Internal clock synchronized from NTP pool, now =", + myVars.read("default_dt"), + ) + + +if myVars.read("use_ntp"): + # Initialize the NTP object + ntp = NTP(esp) + + location = secrets.get("timezone", location) + if myVars.read("my_debug"): + print("location (from secrets.h) = ", location) + if location == "Europe/Lisbon": + if myVars.read("my_debug"): + print("Using timezone Europe/Lisbon") + tz_offset = 3600 + else: + tz_offset = 0 + + refresh_from_NTP() + +pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=1) +WHITE = 0xFFFFFF +RED = 0xFF0000 +YELLOW = 0xFFFF00 +GREEN = 0x00FF00 +BLUE = 0x0000FF +PURPLE = 0xFF00FF +BLACK = 0x000000 + +# ---------- Sound Effects ------------- # +soundDemo = "/sounds/sound.wav" +soundBeep = "/sounds/beep.wav" +soundTab = "/sounds/tab.wav" + +# ------------ Touchscreen setup --------------- # +# See: https://learn.adafruit.com/making-a-pyportal-user-interface-displayio/display +display = board.DISPLAY # create the display object +display.rotation = 0 +# screen_width = 320 +# screen_height = 240 +screen_width = display.width +screen_height = display.height +# -------Rotate 0: +# Note @PaulskPt dd 2022-05-13 +# After using a touchscreen calibration script, the values are as follows: +# (XL, YU, XR, YD) are: (6935, 10496, 60127, 57631) +ts = adafruit_touchscreen.Touchscreen( + board.TOUCH_XL, + board.TOUCH_XR, + board.TOUCH_YD, + board.TOUCH_YU, # #calibration=((5200, 59000), (5800, 57000)), + calibration=((6815, 60095), (10520, 58007)), + size=(screen_width, screen_height), +) # was: screen_width, screen_height +""" +# If Rotate is 90: +# -------Rotate 90: +ts = adafruit_touchscreen.Touchscreen(board.TOUCH_YU, board.TOUCH_YD, + board.TOUCH_XL, board.TOUCH_XR, + calibration=((5200, 59000), (5800, 57000)), + size=(screen_height, screen_width)) +# If Rotate 180: +ts = adafruit_touchscreen.Touchscreen(board.TOUCH_XR, board.TOUCH_XL, + board.TOUCH_YU, board.TOUCH_YD, + calibration=((5200, 59000), (5800, 57000)), + size=(screen_width, screen_height)) + +# If Rotate 270: +ts = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, + board.TOUCH_YD, board.TOUCH_YU, + calibration=((5200, 59000), (5800, 57000)), + size=(screen_height, screen_width)) +""" +# ----------------------------------- + +# create and show main_group +main_group = displayio.Group() # The Main Display Group + +display.show(main_group) + +# font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") +# font = bitmap_font.load_font("/fonts/Arial-16.bdf") +font = terminalio.FONT + +# create the page layout +test_page_layout = TabLayout( + x=0, + y=0, + display=board.DISPLAY, + tab_text_scale=2, + custom_font=font, + inactive_tab_spritesheet="lib/adafruit_displayio_layout/examples/bmps/inactive_tab_sprite.bmp", + showing_tab_spritesheet="lib/adafruit_displayio_layout/examples/bmps/active_tab_sprite.bmp", + showing_tab_text_color=0x00AA59, + inactive_tab_text_color=0xEEEEEE, + inactive_tab_transparent_indexes=(0, 1), + showing_tab_transparent_indexes=(0, 1), + tab_count=4, +) +# make 4 pages of content +pge1_group = displayio.Group() +pge2_group = displayio.Group() +pge3_group = displayio.Group() +pge4_group = displayio.Group() +# make 1 background group +bg_group = displayio.Group() + +""" + From: https://learn.adafruit.com/making-a-pyportal-user-interface-displayio/the-full-code +""" + +# This will handle switching Images and Icons +def set_image(group, filename): + """Set the image file for a given goup for display. + This is most useful for Icons or image slideshows. + :param group: The chosen group + :param filename: The filename of the chosen image + """ + print("Set image to ", filename) + if group: + group.pop() + if not filename: + return # we're done, no icon desired + # CircuitPython 6 & 7 compatible + image_file = None + try: + # image_file = open(filename, "rb") + with open(filename, "rb") as image_file: + image = displayio.OnDiskBitmap(image_file) + except OSError as exc: + if exc.args[0] == 2: # No such file/directory + return + finally: + if image_file is not None: + image_file.close() + + image_sprite = displayio.TileGrid( + image, pixel_shader=getattr(image, "pixel_shader", displayio.ColorConverter()) + ) + + # # CircuitPython 7+ compatible + # image = displayio.OnDiskBitmap(filename) + # image_sprite = displayio.TileGrid(image, pixel_shader=image.pixel_shader) + main_group.append(image_sprite) + + +# ------------- Setup for Images ------------- # +bg_group = displayio.Group() +set_image(bg_group, "/images/BGimage4.bmp") +print( + "Please wait...building-up things..." +) # 2022-05-08 13h19 (utc+1) It takes 24 seconds from here to start of main() loop +main_group.append(bg_group) + +icon_group = displayio.Group() +icon_group.x = 180 +icon_group.y = 120 +icon_group.scale = 1 +pge2_group.append(icon_group) + +# labels +pge1_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This is the first page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +pge1_lbl2 = Label( + font=terminalio.FONT, + scale=2, + text="Please wait...", + anchor_point=(0, 0), + anchored_position=(10, 150), +) +pge2_lbl = Label( + font=terminalio.FONT, + scale=2, + text="This page is the second page!", + anchor_point=(0, 0), + anchored_position=(10, 10), +) +pge3_lbl = Label( + font=terminalio.FONT, + scale=2, + text=myVars.read("pge3_lbl_dflt"), # Will be "Date/time:" + anchor_point=(0, 0), + anchored_position=(10, 10), +) +pge3_lbl2 = Label( + font=terminalio.FONT, + scale=2, + text="", # pge3_lbl2_dflt, # Will be DD-MO-YYYY or Month-DD-YYYY + anchor_point=(0, 0), + anchored_position=(10, 40), +) +pge3_lbl3 = Label( + font=terminalio.FONT, + scale=2, + text="", # pge3_lbl3_dflt, # Will be HH:MM:SS + anchor_point=(0, 0), + anchored_position=(10, 70), +) +pge3_lbl4 = Label( + font=terminalio.FONT, + scale=2, + text="", # pge3_lbl3_dflt, # Will be time until next NTP sync in MM:SS + anchor_point=(0, 0), + anchored_position=(10, 200), +) +pge4_lbl = Label( + font=terminalio.FONT, + scale=2, + text=myVars.read("pge4_lbl_dflt"), + anchor_point=(0, 0), + anchored_position=(10, 10), +) +pge4_lbl2 = Label( + font=terminalio.FONT, + scale=2, + text="", # Will be "Temperature" + anchor_point=(0, 0), + anchored_position=(10, 130), +) + +pge4_lbl3 = Label( + font=font_arial, + scale=2, + text="", # Will be "xx.yy ºC" + anchor_point=(0, 0), + anchored_position=(10, 160), +) + +# shapes +square = Rect(x=20, y=70, width=40, height=40, fill=0x00DD00) +circle = Circle(50, 100, r=30, fill=0xDD00DD) +triangle = Triangle(50, 0, 100, 50, 0, 50, fill=0xDDDD00) +rectangle = Rect(x=80, y=60, width=100, height=50, fill=0x0000DD) +triangle.x = 80 +triangle.y = 70 + +# add everything to their page groups +pge1_group.append(square) +pge1_group.append(pge1_lbl) +pge1_group.append(pge1_lbl2) +pge2_group.append(pge2_lbl) +pge2_group.append(circle) +pge3_group.append(pge3_lbl) +pge3_group.append(pge3_lbl2) +pge3_group.append(pge3_lbl3) +pge3_group.append(pge3_lbl4) +pge3_group.append(triangle) +pge4_group.append(pge4_lbl) +pge4_group.append(pge4_lbl2) +pge4_group.append(pge4_lbl3) +pge4_group.append(rectangle) + +if board.board_id == "pyportal_titano": + pages = {0: "Dum", 1: "One", 2: "Two", 3: "Three", 4: "Four"} +else: + pages = {0: "Dum", 1: "One", 2: "Two", 3: "Thr", 4: "For"} + +# add the pages to the layout, supply your own page names +test_page_layout.add_content(pge1_group, pages[1]) +test_page_layout.add_content(pge2_group, pages[2]) +test_page_layout.add_content(pge3_group, pages[3]) +test_page_layout.add_content(pge4_group, pages[4]) +# test_page_layout.add_content(displayio.Group(), "page_5") +# add it to the group that is showing on the display +main_group.append(test_page_layout) +# test_page_layout.tab_tilegrids_group[3].x += 50 +pge2_group = 1 + + +"""If the temperature sensor has been disconnected, + this function will try to reconnect (test if the sensor is present by now) + If reconnected this function creates the temp_sensor object""" + + +def connect_temp_sensor(): + t = "temperature sensor found" + + # myVars.write("temp_sensor",None) + + try: + myVars.write("temp_sensor", adafruit_tmp117.TMP117(i2c)) + except ValueError: # ValueError occurs if the temperature sensor is not connected + pass + + print( + "connect_temp_sensor(): type(temp_sensor) object = ", + type(myVars.read("temp_sensor")), + ) + if myVars.read("temp_sensor") is not None: + print(t) + print("temperature sensor connected") + myVars.write("t0", "Temperature") + myVars.write("t1", chr(186) + "C") + myVars.write("t2", 27 * "_") + else: + print("no " + t) + print("failed to connect temperature sensor") + myVars.write("t0", None) + myVars.write("t1", None) + myVars.write("t2", None) + + +"""If the external rtc has been disconnected, + this function will try to reconnect (test if the external rtc is present by now)""" + + +def connect_rtc(): + t = "RTC found" + + # myVars.write("rtc",None) + + try: + myVars.write("rtc", DS3231(i2c)) # i2c addres 0x68 + # myVars.write("rtc",rtc) + except ValueError: + pass + + print("connect_rtc() type rtc object = ", type(myVars.read("rtc"))) + if myVars.read("rtc") is not None: + print(t) + print("RTC connected") + if myVars.read("lStart"): + myVars.write("lStart", False) + myVars.read("rtc").datetime = myVars.read("default_dt") + else: + print("no " + t) + print("Failed to connect RTC") + + +"""Function gets a value from the external temperature sensor + It only updates if the value has changed compared to the previous value + A fixed text is set in pge4_lbl2.text. The variable temperature value is set in pge4_lbl3.text + If no value obtained (for instance if the sensor is disconnected), + the function sets the pge4_lbl to a default text and makes empty + pge4_lbl2.text and pge4_lbl3.text""" + + +def get_temp(): + my_debug = myVars.read("my_debug") + showing_page_idx = test_page_layout.showing_page_index + RetVal = False + if myVars.read("temp_sensor") is not None: + try: + temp = myVars.read("temp_sensor").temperature + t = "{:5.2f}{} ".format(temp, myVars.read("t1")) + if my_debug and temp is not None and not myVars.read("temp_in_REPL"): + myVars.write("temp_in_REPL", True) + print("get_temp(): {} {}".format(myVars.read("t0"), t)) + if showing_page_idx == 3: # show temperature on most right Tab page + if temp is not None: + if temp != myVars.read( + "old_temp" + ): # Only update if there is a change in temperature + myVars.write("old_temp", temp) + t = "{:5.2f}{} ".format(temp, myVars.read("t1")) + pge4_lbl.text = "" + pge4_lbl2.text = myVars.read("t0") + pge4_lbl3.text = t + # if not my_debug: + # print("pge4_lbl.tex.gvars {}".format(pge4_lbl.text)) + # time.sleep(2) + RetVal = True + else: + t = "" + pge4_lbl.text = myVars.read("pge4_lbl_dflt") + except OSError: + print("Temperature sensor has disconnected") + t = "" + myVars.write("temp_sensor", None) + pge4_lbl.text = myVars.read( + "pge4_lbl_dflt" + ) # clean the line (eventually: t2) + pge4_lbl2.text = "Sensor disconnected." + pge4_lbl3.text = "Check wiring." + + return RetVal + + +# Moved these six definitions outside handle_dt() +# to correct pylint error 'too many variables' +# dt_idxs = {0: "yy", 1:"mo", 2:"dd", 3:"hh", 4:"mm", 5:"ss"} +dt_ridxs = {"yy": 0, "mo": 1, "dd": 2, "hh": 3, "mm": 4, "ss": 5} + +# print("dict dt_ridxs =", dt_ridxs.keys()) + + +""" Function called by get_dt() + Created to repair pylint error R0912: Too many branches (13/12)""" + + +def handle_dt(dt): + my_debug = myVars.read("my_debug") + RetVal = False + s = "Date/time: " + sYY = str(dt[dt_ridxs["yy"]]) # was: str(dt[yy]) + # print("dt_ridxs["mo"] = ", dt_ridxs["mo"]) + # modified mo because plynt error R0914 'Too many local variables' + # mo = dt_ridxs["mo"] + dd = dt_ridxs["dd"] + hh = dt_ridxs["hh"] + mm = dt_ridxs["mm"] + ss = dt_ridxs["ss"] + if "mo" in dt_ridxs: + sMO = ( + months[dt_ridxs["mo"]] # was: months[dt[mo]] + if myVars.read("use_txt_in_month") + else "0" + str(dt[dt_ridxs["mo"]]) + if dt[dt_ridxs["mo"]] < 10 + else str(dt[dt_ridxs["mo"]]) + ) + else: + raise KeyError("key {} not in dt_ridxs dict".format("mo")) + + dt_dict = {} + + for _ in range(dd, ss + 1): + dt_dict[_] = "0" + str(dt[_]) if dt[_] < 10 else str(dt[_]) + + if my_debug: + print("dt_dict = ", dt_dict) + + myVars.write("c_secs", dt_dict[ss]) + sDT = ( + sMO + "-" + dt_dict[dd] + "-" + sYY + if myVars.read("use_usa_notation") + else sYY + "-" + sMO + "-" + dt_dict[dd] + ) + if my_debug: + print("handle_dt(): sDT_old = {}, sDT = {}".format(myVars.read("sDT_old"), sDT)) + if myVars.read("sDT_old") != sDT: + myVars.write("sDT_old", sDT) + myVars.write("dt_refresh", True) # The date has changed, set the refresh flag + sDT2 = dt_dict[hh] + ":" + dt_dict[mm] + ":" + dt_dict[ss] + + if myVars.read("dt_refresh"): # only refresh when needed + myVars.write("dt_refresh", False) + pge3_lbl.text = s + pge3_lbl2.text = sDT + + if myVars.read("c_secs") != myVars.read("o_secs"): + myVars.write("o_secs", myVars.read("c_secs")) + sDT3 = s + "{} {}".format(sDT, sDT2) + print(sDT3) + + pge3_lbl3.text = sDT2 + if my_debug: + print("pge3_lbl.text = {}".format(pge3_lbl.text)) + print("pge3_lbl2.text = {}".format(pge3_lbl2.text)) + print("pge3_lbl3.text = {}".format(pge3_lbl3.text)) + RetVal = True + + # Return from here with a False but don't set the pge3_lbl to default. + # It is only to say to the loop() that we did't update the datetime + return RetVal + + +""" Function gets the date and time: a) if an rtc is present from the rtc; + b) if using online NTP pool server then get the date and time from the function time.localtime + This time.localtime has before been set with data from the NTP server. + In both cases the date and time will be set to the pge3_lbl, pge3_lbl12 and pge3_lbl3 + If no (valid) datetime a default text will be shown on the pge3_lbl""" + + +def get_dt(): + dt = None + RetVal = False + + if myVars.read("rtc") is not None: + try: + dt = myVars.read("rtc").datetime + except OSError as exc: + if myVars.read("my_debug"): + print("Error number: ", exc.args[0]) + if exc.args[0] == 5: # Input/output error + print("get_dt(): OSError occurred. RTC probably is disconnected") + pge3_lbl.text = myVars.read("pge3_lbl_dflt") + myVars.write("sDT_old", "") + pge3_lbl2.text = "" + pge3_lbl3.text = "" + return RetVal + raise # Handle other errors + + elif myVars.read("online_time_present") or myVars.read("use_ntp"): + dt = time.localtime() + + if myVars.read("my_debug"): + print("get_dt(): dt = ", dt) + if dt is not None: + RetVal = handle_dt(dt) + else: + pge3_lbl.text = myVars.read("pge3_lbl_dflt") + pge3_lbl2.text = "" + pge3_lbl3.text = "" + return RetVal + + +""" hms_to_cnt() + function returns a integer value representing + the conversion from the current hours, minutes and seconds + into seconds""" + + +def hms_to_cnt(): + dt = time.localtime() # get the local time as a time_struct + return (dt.tm_hour * 3600) + (dt.tm_min * 60) + dt.tm_sec + + +""" Created this function to correct pylint errors: + 'Too many branches' R0912 and + 'Too many statements' R0915""" + + +def ck_next_NTP_sync(): + s_cnt = myVars.read("s_cnt") + c_cnt = hms_to_cnt() # set current count (seconds) + c_elapsed = c_cnt - s_cnt + if c_elapsed < 10: # continue only when c_elapsed >= 10 + return + + TAG = "ck_next_NTP_sync(): " + my_debug = myVars.read("my_debug") + t1 = myVars.read("next_NTP_sync_t1") + t3 = myVars.read("next_NTP_sync_t3") + five_min = myVars.read("five_min_cnt") + myVars.write("s_cnt", hms_to_cnt()) + + # --- five minutes count down calculations #1 --- + + if my_debug: + print( + TAG + "five_min = {}, s_cnt = {}, c_cnt = {}".format(five_min, s_cnt, c_cnt) + ) + print(TAG + "c_elapsed = ", c_elapsed) + + # --- five minutes count down calculations #2 --- + myVars.write("s_cnt", c_cnt) # remember c_cnt + five_min -= 10 + myVars.write("five_min_cnt", five_min) # remember count + mm2 = five_min // 60 + ss2 = five_min - (mm2 * 60) + t2 = "{:02d}:{:02d}".format(mm2, ss2) + t0 = t1 + t2 + t3 + print(t0) + pge3_lbl4.text = t0 + if five_min == 0: # five minutes passed + pge3_lbl4.text = "" + myVars.write("five_min_cnt", 300) # reset count + myVars.write("ntp_refresh", True) + + +def inc_cnt(cnt): + cnt += 1 + if cnt > 999: + cnt = 0 + return cnt + + +def main(): + cnt = 1 + wipe_pge1_lbl2_text = False + print("Starting loop") + pge1_lbl2.text = "Ready..." + myVars.write("five_min_cnt", 300) # 5 minutes + myVars.write("s_cnt", hms_to_cnt()) # set start count (seconds) + use_ntp = myVars.read("use_ntp") + rtc = myVars.read("rtc") + otp = myVars.read("online_time_present") + # print("Starting loop") + while True: + touch = ts.touch_point + try: + + if use_ntp: + ck_next_NTP_sync() + ntp_refresh = myVars.read("ntp_refresh") + # ------------- Handle Tab touch ------------- # + # print("main() value touch: ", touch) + if touch: # Only do this if the screen is touched + if not wipe_pge1_lbl2_text: + pge1_lbl2.text = "" # Clear the label + wipe_pge1_lbl2_text = True + test_page_layout.handle_touch_events(touch) + if rtc is not None or otp: + if otp and ntp_refresh: + refresh_from_NTP() # first re-synchronize internal clock from NTP server + if get_dt(): + print("Loop nr: {:03d}".format(cnt)) + else: + connect_rtc() + if myVars.read("temp_sensor") is not None: + get_temp() + else: + connect_temp_sensor() + touch = ( + ts.touch_point + ) # Just to try - it looks like after re-connecting the sensor, + # the touch data has lost + if myVars.read("temp_in_REPL"): + myVars.write("temp_in_REPL", False) + + cnt = inc_cnt(cnt) + except KeyboardInterrupt as exc: + print("Keyboard interrupt...exiting...") + raise KeyboardInterrupt from exc + + +if __name__ == "__main__": + main() From cd46824244fbd6e083c0c75ef9b790ff106279c3 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sun, 15 May 2022 15:44:32 +0100 Subject: [PATCH 064/132] small correction in example bug repair --- ..._hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py index d3c6789..65b122c 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py @@ -791,7 +791,7 @@ def handle_dt(dt): ss = dt_ridxs["ss"] if "mo" in dt_ridxs: sMO = ( - months[dt_ridxs["mo"]] # was: months[dt[mo]] + months[dt[dt_ridxs["mo"]]] # was: months[dt[mo]] if myVars.read("use_txt_in_month") else "0" + str(dt[dt_ridxs["mo"]]) if dt[dt_ridxs["mo"]] < 10 From 9256ea98deda3fa2bb9788a9f3cb1a96f4dce5ac Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sun, 15 May 2022 15:58:39 +0100 Subject: [PATCH 065/132] mod in .gitignore idem --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5247efd..544ec4a 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,3 @@ _build .idea .vscode *~ -examples/hotplug_sensor_examples/images/BGimage4.bmp From f3d0ac11c8669759b19b33785144357646c50afa Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sun, 15 May 2022 16:07:28 +0100 Subject: [PATCH 066/132] added image file Added BGimage4.bmp and it's .license file --- .../images/BGimage4.bmp | Bin 0 -> 530078 bytes .../images/BGimage4.bmp.license | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 examples/hotplug_sensor_examples/images/BGimage4.bmp create mode 100644 examples/hotplug_sensor_examples/images/BGimage4.bmp.license diff --git a/examples/hotplug_sensor_examples/images/BGimage4.bmp b/examples/hotplug_sensor_examples/images/BGimage4.bmp new file mode 100644 index 0000000000000000000000000000000000000000..02d4c259878ca392426c9f0530e94918fb219cb6 GIT binary patch literal 530078 zcmeHwJ#sWVub%u9xXRfL94qt+oLcY6&R69MVy<-h-jfA^Aq{?osGdHIit{p%Uwmw)>AFWa>#mY0v0m-PQHA0I^0Yg)d1eSN)r{qL`r|MS28=gZ6M zTe{xUl?1P!>H137@0XXimvp_RD=psM)Af-Wpc`%AiB)Ag3F#Jqo`>oZ+n z>H2+%`gZEnV;F`bgJjy1vr&J0myyC>H137Zz}ukHPN?py{GFVU7zXtO4o0KmyyC>H137 zZ-VRNHPN?py{GFVU7zXtO4o0K^7A#(w{*Ry>myyC>H137Z-V*jHPN?py{GFVU7zXt zO4sjg3*LUeCi<4H_jG-v>oZ+n>H7Whk?Q|=c}-WY{5@Uy|31_8m9F0}AFnUzdQI0` zy57_Ek*?2leWmL+ZQI*xqHpPXPuEAfKGXG;uHUq!@2`ozrRzOiAL;r`*H^lJ({`sI zA0Kb&dQaC!x<1qOm9F2^3ZJiuzNPCuT_5TCOxIVsep8!#y(apWuJ?3(r0X+XU+Mb2 zwa~}!*F@ja^`5SebbY4lD_y@|zEb^PFR$r(OV@k4KGOA>uKa($skL5T6Mak9d%8Z- z^_i}(bp58bdwWgvEnV;F`bgJjy1vr&n_BYyHPN?py{GFVU7zXtO4n~{*N@jk-_rG- zu8(wmrt2$Rzp0f!UlV;x*L%7?()F3HuXO#UHvf7}^etWQ>H0|5=ga^3fB*9GKa$=@ z^7r!cFWdjW{L8=ORl3su<+swy|4sazfBxKl5HvV55@y9ep&8UG0(maeXmI*@P9(?t z=?uZJRmA%nZH1YK!d?c+mZqwyd3g#MpxA?SR30pXdPCrLbIC|>*KF_E+bV0;Zfbta z3;fJkJ;rB3f#R$PhAdWI5oqS}Y|GK#{Z18~!-%la_TE?wxEZtJkWXj#XTHBlKgYm8 z64W;W>LzOq(8@%w0F%0h@_U&Vioq3FEVyj=SroAWL7gISu*oz+F9*_2d!YQi2$D=U zDc;zt#*`M2`pDZM1IR&rBGBLeR7-AwTg)ZHv_&ZF8F%f>X8+gvxO}i2V0QZmox9kA zA8i=3v2u;T+8(3l9|oizh5T+c8JEc~x>B{~^4j}EEvbQ=NGJ+^F_#R*6Rd7Im$Df% zSTSE)%Sd3%oLQ0YbDp3>e{>1jmJi&$b=}xUA6rnnp*0Q(J2#N^cGMuk1KZWGoTLdP zgZf55+j44wQlF+;%V<5(?zI!NAKXZ%8V5_tyXO-Xd66}DsyS_x&}>nhmkf;W)md+r z>dq9oS4gwv;YjhLh`gL^x5!h%vYW&t2DVAY%UF3vKyLb;E4A%K+z*;e9$zY_x%t7e zq0-BK#lkTH_AQ@22-HcGUh8aVjnN%1Z@IZOr$?ce z%bK~w4)r2DzKoDZo*P$~J;$P0`9)ygsa#8z6>hJ{!k$c*!mY3rjQL~W^Z-e2yWzY< zkg!m>D5%4+C{}(Ekei-4u0?QrMOM{h17oAPSs^1INPCn!z~%PSJytrW87sF4*tfjX zeq6QYW^yhym!q=TNtAZ7T**Ompx6$e2VQcy_He8jE4K*PJG|3ITy^cHUS|!-E1V*- zJ9$FQtt4PAK_YY^YdL;DR?ZN}+srASaYa>jhsMQRPJq?{6q_VP?IdO?G=n-uKyKt2 zSN1$BatCPK1I#71M@#cM8K599vmEm54VxKxb`mSM2n=>3>Xc^svT)hBBAU4MgqTT2@tLQpBn< z!h>@t!k#89f_g-tYH7LUz2-07FI6?}s=2HH%`uoA;-ne7(b9f68H%tc28*B`5lH)t zwB?pxHJ5OiD0#gExiA_B)2xd1#R*vQV&=?>CEj3wJJ^{+pxB_k5vaP~+>Jd&9-=HQ zn2>6D2Q10E989wi>zK<667k<#FD>!pi>mu+Oi-`F^+Y^GSqdlew8Y^FX~)l;h~sSm z;be;^m@2hS@Z#oSW%k6l>{xk3V4@d?PcNR+)4l?PwIZ!eiFR(j;nDD+Ufrda6s4Io15mO*+A0wi_k$H!P`$Hem_Kg(3mYW;A87Q+| zSMl0*x7YW$nj0|OW;xMAjs>yujKEnpmfFq~xmQS&TgPnKQ!H+JLL{fi6jAqcz~J)U zcCv)_d!8&s($y^rzZENw2*^#}bET%ei2I=@<7Vke;a125L*3uivkwM&M51dr8VvZn z1J{A2fV-0cu%Mn1*llZi1NBImeHP?EC2!dgoSNNG^kOHIF>@C$7dLCTJ4~WP$y{wV zD?rD>F#`52m#reXOTQBif=O>>z92+Gu;*N{JXh^Hoivl>eKSYlQJ%ze&lSB`I7Z;C zZ%b*KqHG+}ECVGwM|0DY6*oO0l2c@gh_b#m!0o-r5}MCBiEicqN>I-T$W7mKrMA7O zYJp7%RnkO%NW0lCmR`)J&rYF(_--(w_sB;=k zuu@gy%;Vg2s^-&`%mP`1HB5r~Lm>AiXMM&MRoT*VXd2ljEFq-O&dCsV&K}{xHG!a( zX3Ql}a!>O%a}j4;QSEd`@zRkMyUsuryN;~nrukH4ib#t#EJL0YZw&`rE= zF#>~qi%NTD+UTKCll|TlPF307jD0FHMbyc}25E$@yxq zZ&7W}OwJ`V+g=e()^h{HA1s?Ky~P?(2K9!3G9~RME2`8-m`mAJ!)^efbn~OQ*PdyA zVAyWST%HCm@g7(6Dj)!EP|pZ#&4~g|J5^IG{od&+*j3(4SAa_7UH^eG!@sBv;GNprZO^A8i$cL&YE5GXe0 zl9BMgDw81lTjhGqkG}1V5Tmq7!S>vQY;Y>^LDp^!HKwMR%VqO^Pn?kr6t+1nzP#mX}R zsRxk$SvwTXo+5-K>vPSR%)04?7_Omv;3BAJ1ndp4XrLCk+2@U2*h~1}xlRT@ zPeYU*X&1`sAc0kFVbc1fj8cu?GM&PUkN^NI~+z^`PRfn!Egckn6WdQq{ zG~pwtV+8CCuxOw(H}+&Yn%IPnsGJ~=E?bf)fC%as0eh#;4%B8>5Ypml5zb`@p+$Ib z*|jCK_q6aA)Exq6omvXg6xE>_oXZkW+MRLI%<26uiqNpuWHFaO&^^_*Im=3cnxZx| zJ-gynL}2`?(gYwu9U_ohfYUzXimL1!b)f8X zxj98LGJ@nf_q#A75!WOQop5W?WJqG=4uRYPob(x2R6CsmFC7tw*o1b?gLpBQ#}Gmi z)G-3R8A3T7nIdXNuNf%GPPtX)&unK-poWrYvRjU@&++YRIQW91Ejtpkws zX*+0&>d;8xv>VOvB0H@?rt*;7;71EkiMeDXysz#vmyFVBylV&L3FdN53565(yz~Qf+fQ?2k@ZsRhksbjMTw#6pe_-xGETsc11yO5!5pR_6AVfRujq)c1>xgaEeHa zHY{6v7u(Bv{KIlzgy(LI+<`!^JNmMH2PE5zs^&%7*)^q|#%VrR%1|!(T*C>h1p{og z%9BA(26h|AOsxDOVD4K@QEwe#DVWBtVKr4D%M5=HDMYg_zsC-3WG^A+5|}+1HMfAK zsCBWl(=@5a_|sonDqI%*(7D{B@?`z_Gt1d;>(N+D50ng{xsjTK9QJR}tlR=Vg58p2 z07Ov72-v%EcAz%9f{+$Zi*PPO2ra^c%dRb(o+^rl<~$c`hjej_V#* zl94_$Cq>L_X+N9{Ma(7^a|s09)3X*R1uBXp!YoLxJF=H4k}fZreK(Ej@mxy9rCgc) zrCu)pZ$1I`H38rwsAB|18(@5(hUXG!4yHC~cKcZyh%lgfTrMO*9V0N<{PHX-b!%Ss zCmWo!U%qxH7%{XEo6M}Zr1_6(I8D5w7%7RI+OKa87~1ALH!}HbpX=V+TqH9LWpxW(A1JqWQu6u!R&jz zEJ_qe2K9%))__P`>&EK_N}h9CJgGU(X*GC}4bCOtq%C4DR(=sM&*iD2IzmzixO#IU zHOIN0Pc7af%3?0DD?gT=jvJ6URn$gEIME*EL!jDbb5Hja zOS5!@Kt+l=?Uxk#y3$hN6j3+cmEmsTb5RMXET~HaCI+F~jG7++BRj6^=AtS!&74_L zi~Y^ARp9}8P?rd3^K>B7I!BufX=m4zb{ePobRx5-dGf63vKu35AaF2yN_!}x%ikUx z_>>bh?M5+FL^Al}a`qBpF44o!NDpR6X%9uD&ZV?dCqorVKY|m?tdsAxTUNp|HtWx; z$=(iX+iF4?!mcUp6iyLo(H=^+E}5U#!_Qc;y{EO#(Y$PS1-etsiEm~#pRQy;$)0rQ zo)%7mdPd-^1xjt2qBgQk=O}JSgt^o>dE2~cB2Ufi5oE}-frSu+kP@|U9XBuw>KTEv z7AUnTidw(Rk(HWqye^tCmklfu!BehmSS0 zCCLDYppFqRH@{&n0fY3pH7-PI7pp?)w8J4pN3^8fag1Mgn5kZ_Eup=qg}j3NC{Z98 z)E@#{J0fkZH?JEgd0=Vrq~TI+p;DHsy%p_haP^0rOm*DykzSg#f8HCsK2q z>-p5;J)$h;61(za>FKxunNvk=goKmX2S_-%oZMPG-?B9yEeuzz{2`Ef07;*>!+@&h zRB@x3{S?{hX=&Rsz!lUZ0;}c{wfBbmppSa0nwuXYBUpf$1WA9M%(?(6sBZ+St&}aG zaEhq=SphX|ChvA09#Xp_y)Fl48atN7!H$C9W2&SzPH4125`B2dQ0J`2iR zYEGJt(^P-3Y_{~>9j?P(jFcIH@wvRNbIN&n=B7$9sY;Id+6%2A^TI9qxQe;t7I}tM z>G-42cY( zxRHuKi&J13oKglpR(=t%cfZm(niJ}(0+6Qq<7Gg}4n%`)-Xk~(>KTEv7AUoyDRM(d z&8BmtaL<)^+s8nkBP#^-%%Q$Z4U)BR4Z1Ox0L?qyPX_wE*>baDXP}BpIYSho2s?(1 zZngv`y?ExDiX=P7!78X@1gNJ`fWpbBcT+y(WAz`i@UhAb=GUXg{Gtm&0wRViuA#2v2Gd>*cV zJzG)>TG_l{0$f3s6>hHxp_H_}A*CA!pB)j$6O$;NYIdGwrTA-#0JuRNBQV$i zs8lnPBSah~_`+G-Xd#|e7ITTt_~~@8!vUAwtUIOSZtMXaYp#U_-h#SAK$#*7zGN?NQv<_c5P~0n9K)|F$|B156xdfc;hVlEca)!WQ_oKQ&v!pI8 z1tUd2nwu;haK>CR63$nH1BPk`%}T#f=M;9<&6C@$DGz%U)E@#{2Ow>&9TpALsT)f! zTAt4!>-_yrbH8EwU;~sv{UNY!E>U}LFq*E?R6~{!=wVm`gEeU$ar}O)ydhwo%Q3~~ z^L)u%GPGxH+k|V9fuG0q5_5??`muCu+yK*cEj>9W2!4K?IG@Yw&}EonV{#q+L0cDe=j$1@2!;=bIEP++^f_DC{Sw%Ars8>K%E-O%#fwM z!zoR8`CiVR^&l)LZx?{^ij_kI#;0=E0b9qT^!?02(%LBvxOZ~cekZ~G*(tEJ2&ynK z?6Go)z}mUgI;H6{WTgh1Ipb3>RFn@|41xnvA;K*@opRGx`z zFtcMFbIC3846D-d<`y_pWK^=IQsA+olxPE$oYl(pT1s-% zEG^MHc94>nr{GYo2F#fZK7u+%;B1r8?Wx3CwO&g}#v)4@6RB%3*kMN-wyHBOHWk0m*WEJZGwrf1pJ z1xlCzS5S8d$S!WTHA_oLQnlvlHMywF#3_4`!lz~^Wim4tQpkvLou)teTcL-=b zyl9{X-2g%@vuBk}o|gQ~Ab|mtLERxBH&Sv72de2Dz$D`ZH#wJpv)wR$KUU5V7@P%E zH)xjBg{5Gm=tpyt#RJZmOGd)^YH+|%?VwrHZwC2O$0Pc33n} ziW_?_&#T${y^;c1b1zaf0Z>qX2&|h+)ZQEJrgJpakX@!yVg^{+JJpQ#k&NGul{W;& z<`UKQW>1rG?~KJOEjJoaOXlHaRIJ1dNyl6=63@IEn-d^$-I)B$X|vy)UWYFBD5z%y zQV$^g^L7|e)toABG_#)~vk$PU3AloKL}1liqW0c!AB=uaRde%0WOi8eds@I1)FT2z zb9pJy-Z`YXWG)%pI=l?<44irf)}?1aGB1H)E>@lqs5Vw^y22@DE&@7jS4hwuyf$D?Ht987X8^}3M?&xDijQRtQ;b+ zb}qF}Y3{l-)gLUIExkearR=N2o{W^!ZUTg}hJfDm=XujP=6GAc5?zERAGmpY22PYm zh@m{4YtZF=W#nSz2!Zu;$;IbEksR}vAtEs`QdQ&N=HlcMxs(tlj`53?Uj%mB zTJ3C4CPsnF&Z>5Tw>pYwl_$-TcX{tO$=1e>4ckSpVFAim`6rHc6)Dx z8eOo`aF82!A~WlS!*NZr$K|xz*L++dLQua5^g0~XbYzO?pr>e{FeVpn){SO|5HXiP zDX3orIlY)9hz`p&925ONTd)~e@V=lc;(%QW3 zUAuCiP=h`C&(K^mmBkBS4(bkp!G1@5cC*VkmtNT{$KBWide)REUCjaJpzaVD>|)e6 zXx4OC!>)1q3|=n45W1GHvFK9|rMDcvA1hY~jE>i$fm-ASP>)vexOOp@*qfhCM>~4$ zK#fMnUOlVbT6BR{P=5$acKE0n?#P;F%~3bN_gU>?F0sQuolbW6q*?QKW(~W>sb??d zyI8cXRxEUa`a@vbSEQ|NvXm_vs6}pMZl1ZAOZ4Ior&|*P1A9lW87OR5 zhX~Bg<>;8i(`9N6J7@!{np21E7%5*6xX)YyZrMeH?FT0#9bN~dH9jKl%?)H-Cp}=+ zz{zmM${zx$2avSA9hwfX8%oVVH^_6gRVg^?y*D?IwM1!_W4L1F4}rAnNZQ^2g99Z) zAly|>q|4{x76DUmj)g-62IjILg1SPW?4KAKtvO`#_a2)VfUGOI!q2*qcF)IY(2vL%_ELFUq{_`<7wJvcl~ZSvV+zPtB|uXVJD~hw#t9iSl~)A}ID$25f_RMnId4jtr%C zL_EM-k3qBBM-a}sAv?6{GjK7N=!u{i0c|omGJw_*sdEXtOF*!io1Y~c-H3wr4kln5 z)Gq?NO-*lbHCZaT!fJ+6Mw5888|n1{QS>1O~eiK?cprR9>d^S~s)d zAKmVP6Qzma?tZcrME4~D+@Nj|*l+4lGb|dYMQ-eQ`_hcLbUR8*6SsHm%7H=&_UJ!D zQ#k{VJ}xz20CP}x2x!~dk)ghh=%A;%_h930>;XM%9$+|I5?~JM4uQcfM}324O}{nl z8mG_T~-t)FLJ^}4;SYg*m?*VlGRk{p3ZN zw|&1eELm2#y&?+-W$>w)HRHUst;J6I)V!>b$#}Ees;T5H0aighA~4uTC{Z)(wL7=V zW;yG|VkcAUB?B*OWHR0?7jwzG5-aM=W@yR@+37Jr))5u6^L8()nwyYWz}}+-tDt@n z*zYROXm7kG25ONTEz^*p12Ym>2lb19*3q{cDBz_c}2k9H;4EWxkb49(_9mx-o8F90c*01%q36?>KK7-G?2e}PRxqx%&NkD2xQq#Ue;vU`g^WHX3tj!zr{L0|D9XlDo-3Z6Q#*jA!RyZ>7Dd%qL!s*q)U1UOp|!d(XB$ z8MXD%sY#x5Bvg>s*K_TT!Fy0|2n_ZE%CnnMt28Y)?nVZLy_NQ6E9TOQUg+H)0om`T z91=WLR1X4GcpL(fQJSZ+eIEQP{q#=CTv&dePD`5S)>b~-Ej3lUB&>2jmC$aMq@5DbVB9Mx&o2iZhPSviwb`oK&1?N58kE zXFhn!+VssW?1=W>+kfXPZHViAH#>`jW_ONOXgn$c+P*3>MI``zNN`;MM2sY3aR(=z+2C6cQpa-C1b{7!v3@;x=b zTfva3ARj1a4F_*Q9U`!`0P;TT2j~sA5jSBDG3}-p?iMkZ84|gFJCNcHKL~7FiFD<@ z?m6f+4X{__+0$gFZc4mOlewc6pGN$>Xx6RY=QX7!U-Ma)E!xvkYH3{i8`12k|IKav zo6PJn$E6?gf6PJBK2J(7tQ9MF2vq%W)(utXoT)Mlnr6&p!70O3m}y+37xot`cL-Gd zkav~4L*v#ojut_e^-->$F6o4#e-To@ub-CrsW5*ROBR&F=&O7V-9Kw`26&Rq)#NCs ziXvXk!9h@u2&nzQ1=W3XI+aH)Cfje?4ZG+3@~WP{n9DNe5~SdKAaKvQlm~%0Bbt#t zk@cbFZ(aG@P(J-_Nx7Q|sn+*1_{=D_g}= zhV}0=bB6pwalqTT7MElRCqW$}VDErU6P4P{sBySku5yF$lEz#z9tmD%V&xVA`+!Xj zlnij0QotpJb`JJL^Lba#X6CXazrX*XDD^A!>)*HR?e_1~K5XmS2mRX>R6_PEIQR(a z7Xf=WEE}jTBoMR5mzuCAn!7#bGGmcZlGp_25dqol8nJw84_eP;wyVEg ztxqVLU-DeP*823n$wmKu?C3Q|kUzDz^EGUd{{`DJQRD$qI~Q{a%)C?ko^P5c*KXEr zxp6l#AnZY7E*Xh9FM)+;D*OGEL#d~V>PNpSw1j{TXnroFl<2iS|8O>e)_Pb&Uq11{ zd!O=Is(D6)mXZy7COPlzN;g8D;Xumez_-K^Vk<8EX?*w-}XvW2=vC)U0Yko|tjp}12;^$=8r zwh+)_%6GDPLg&uQ{`pG&_OJPW0VSW4bq*t^CbG=-*8z$QvKOp_`bA*08_K4S8UiA+ zTi^x`nZ{hwbTcBc@`}Ldcr6&H9P$F!Xmp?~?eH%BZ4W);rWlhR9pLM*-TGw*0 z59$zstxb?O^~^B`$>7I%+ho&jU?}s%yF_CyB_6@KMBqMi322&ulI)&?S^M0SHCfhM z;ak`&qZ6!twVsz*ueQtU-g~VM@%V4|;F*`|ldtXH7*Q>xgSz${B;&ZSWvm_=fwbw! zZ@>RXveWYtE~#-Axsgtp>#brgd#J>FZV-rmD#nxoJc6 zK?e@%b?t;@)2W5z0H*1Fb;8~OBvOWRxyZj?hJo?TR+LX`yE56A^ zG{RCw%rex^)Q*JI?BK#qW91eBxyz><>O56!hMR|dvz&DUyS5wge(rhxJ;~91Y<(vh za|!H%J`w`<0h=5s8Gr_=46PK7aXl0bB;ynCqUzR%|+$+Gmw980!covaC(tf=;n`%{I~D@pZ!?~Yo_cM(el4usq@Od>wK}+ z>a)w}Lk~WK`bEIL=bI)9wVPee$8xw$y3qn6sZ22sn6;S88l6~sK|t&GjtpgWL~`;} zP8E)afJLVHETrE(9zQcu^7ZS{GhgkQyyGmz{PPJ}`=fQ%$@kRsU2pHC z_z3D3fzkb6G*FA&^l*>4?4c6x`9k1(<`Nii z1@(r2eZV$Nls9PB919I=bqc-xsIw%maAIOE|4jdVtMl`cw0qwY)wcL=tn&%TrzU|S zU+KK0zmk<%UI!t3WiMD0F3iQsD*~gvQCeWs5CDy7KkHMk_Z_P3ysW+Oe=Rnj(e$KA+0?JuVt-!BtZ%^q z@}T|@80&{p-~flg452#n1_sc_7Uhep~B&Si<-v11vp z=(MEQ`jn$JrBc7rdD%N#_ty10d}`vkw)UFWc+TbA_IKi05AwXWbFhl1OGd)^YH0tt zQ#yme!p*0t#RlCl*831F<5kQhV-YJ?2zn^`j!400{MAR zzPmp`@h`7&US>*YwI^nl&>eN1+rA=+wdB}xZ+9f)_haP_fwaxYnL5$J4Gz>%h(R~V zOrKfSqE*agi%9Se5V*%&G7RFw-u^i-qRGK%#ovYIb4&h^-})6#nC*F)?VtxA`)AJl zPL7&SOwuOZ{%LviaYdG>W1545pdJxO+m5tz2Vkw9NwcleIGuH)+i?Z7in(kN3Elw$ z)hyM_3``xqgKvKOvGdo78%A9_Dw7v$CMG zdHbiC-T#UYeOxgxsq^6X?H~yVRp3L*V`N0hHvna(ldc`T4?eM(0|Cb}2OJ2#W*Klp^$*T++ zoJ#}-y8|`a&ARP4>!xql_9nFWUzWsN0+XOV5U>x}rir2k&8pAvC2q9vNReoM+H1d& zrN7}JAN-1MWb-@u6r>-PAFa;LOFqEJ1M<5S2me9+B4F>0%dv-2?S@iwksIk$a!8SA z%%#L5I1dQOj@G!90|jKXc(XG2ZYj<`qWOuCBJeA|Bg&TaohqI+S*N$+^OC+}sv~E8 z@ML>S?&y9VF@t(RV6azEmfh?!&ayej-HZf;cS&O|B_6>&G6ME~-!xImpqZS?+n*pv zv!*!vcs{8Je$A5oiHHAo&;ER6%e>0gb-cVL4ZM3F4$*@8MPRg3n)yQE-{j^vJR~)Z zxvbHM^&=zjJp%VyH4W-?r8#p=dch;1vm`jOAaF2<==y**Il$_@R#b|UG+U;P$lut@pkuQGD@3MAp zRiB#hmfzd!+Vi}H=02Zz#|r{u{ZOhJGt1gAt=D(>9Rk8K#Uz1JDg2t>XYJl9=CX%M zytfho>PL7yO(q=>EUnV?8g6!-K`GDq;w=2nR{U+a3_uHWrEQcNvoA`}e(~wNc*Su~d-05KR-AxdF0-;dt2W8Gsr_O}1`(fK!!@SEw`H$UvF zUCB&Z4m@I!^*P5;vaXF|tysB3pxR~X4pg9UBtm;g#oj6=4@s+ zv8&6CwKoJ(OHj(PH`MWxs&=k%YByY?S#M3uWsOFx9}a=k@|2V8{bq#Z)1FkF**3FC^Y(Qf!fke>9MZi8_nTx&rfKoH&5?BZI zgn;bgQx2t_D#|%*xQ1Qh^wMrqDbLqJ4! zi`+=3#~dUzjk&DRi1lM3Fgjjq1_~IAM!(h$_L-hPVb`)6siJzgsKVnAkaR~~@yT}eO8ytPsG#~)ek04L zeW+tbSxzo8U@itA#v73D|Qj@uM_3Ib?*L~=}T2P;r*=IgYu5ZD?CIa60zxWR$q){!9w-5|61zGV-zin(kN3H~7vxX)a2 zsX1QZjZ0XpY>@708iO;so;5{L5FqO>+$wP3q zjT)!3Zf5O{wk78B2$^{Q+Yq?tT#A7bOmpb2ku@I!hY+9L$;#hg=G@?_mnWn>nPzvb ztgW^r3CBS_AyBr@+(%}`X4t54(6)_m)~ROKcIwf##9SUB6YqZ;0{5FsIYM`s%O;=# zG45o^LcV4hn@XP#&2iGPa*Key!xjzHA~yqhD|-`jselurZ$x0AzwN50nke{Gar{(o z<{pvy6nC=uFJdW|`nCR>pZq?2kj^7=+Z{X-3+fnw!5%}UcC+T`lE!A-jXj{$M5I2A zx$NT-?|wG|vWrhSqo~7DG#(uR>PKXG&Xr9+SJj*@ za&sI4l5sm$-zlL;TU&w4h3_4h-l zBAKt zojHHzV&xS9>O*9I&Xr9+SJj*@a&r^{@7rk1r46Uhx*r0gP~T{Ds~z;LRJ)Vi zpO?4Fnoqhl5voh2DJ-un*X#iKGV2np3u6txloW z8}(YoYwJp%%l5=PE}kSf_cX3o1MEg+TxE{PT&%nzK%Il^&$+Vc=c=01NjGrW>)Tq! zYwIfJ(u!2*-2;Kq@tPbc{t(XrOJSqYVR&W-Jv$wl%d_ZQ;P-0Us}IdbLtw0PO7>%B zSsSMHy7}w!QKz-bg8)!Dr7@SM5QV}W5g40=lGvD;9Gb$BlfrIOS|XfsHaqsGue7;r z|Kca-4R5lBTX1yGj(8&++r-Kl0$U>?XX+{gC)@A5RoXVbgcx;$%+8)JIUHM@tzs_E z5DNJn5xCD>azQy>;b<|!o~Qc%|j zq$WrHTE7dKU*mXZ%_ts zgE~fFa?kB%-Gcyt+1;FJ!lQ-edCWg&-^5Z(`5Vma|11|iy}w1%0zv3JI0A#6gK7rN z%55guHS7wf@L{1em5(%+7g*NdVu2uZ9vXqs@mkY3v*!t*)Ut-op8opv#~=CZtA8*L zI+ee{)S_P}o5iKE+m{~iI748xkJij3KpKs1v4hT@KK@)H=QX&%TTp)p40Zqtw3~Gw z#>U;81%$_AihEb0bY_y*^VfTwm&pFC+U9&b_^^bxp#BgT>;M!vXx22&g~dFOQ;q8m zw{VKYj_D)MrB=HpBV4%Vtjk=iydpq*j_l95MFTbI#*!y=dXy%UBz$U8)%t6FUY?_b z*rS@5Dda+aG%n^6SU(pX?ws>hId7x#i9Q+~*lTvs>Cs1@OXRH8XP3cSP;Us(9$P-8 zFZYos(B2#}#FcK2!$Y#CxO=U?hyC+UyleeUN&cH4_&zRP7Hj7&uoxnYXd>UB-Vhk> z929umnwG{f-^KRB^+G^%Pceah=JI@3P^GpF&J;@}5aP>ddDi4L8h{t%!&N8ab$(t*0k-?E_=qQ2%5 zxu5TYMH4zf-63%KD5ktGj2JysBs*o%Kux-7a@o8fPf6>u64lj|PEVTM`u*Noo|lLN zP2$&Zy}NXrq$4uq7}OmCmqt47DpW*@;3fyEX)5V+mLsPnGqLbBmq>jU326s!K^-En zZ6)%S`>Jq?s5`L-ANHeeEO|mFQ%og2L-wB_^Sk*Zq+GOD?Yu)q^2O(O@jp#Bg@ErFz|J1pGfK=m4KBD&1;dFIlB zysZ6%gTtWy5J+2#q)&F4HO-2b`8^0R>c*BQwDz=jUjF)(Ps(4v@;&eV99kQtZ{Ut?Nmo?|G_lb)3k|QgE8g@Y)B5=RClx?-<(Cv8PJ>dIT znl(y*U+Mlf=8_SM)uSOGheqQ%qj2=GeKR*ePYtkr!;15-cV_0f{PWMh|K@)slFymH z|NiIngOcj!()PU6qR+~jn~Du=OSL&3^y0K+B)qTeeY9vUw}3#+9^I}#uxX{{45J>YhFd&vZ7kLAy)HL92poopG$aAuzb>C~wfLGz-~X*bCDLuMI)= zzUERQAwZh`6abDv{UJadfV|JSMFTbI#*!y=B+XNrpERjLeD6ai=0E;=p;x3kv@V+|Rb94&2adMyf7SEyQlFIh%*;=h?Rj~>(-QYB`zhs0vdqS@ zR;;`sFxKy-CCCg7GRy&`(dbq?==JC$&n5ER;{pkN%-J~Bij^+}?lw@(1Ougg|3R^T z%pTi8()KOC&nueDd{3Ky_`6v8>!1B;shyX@2paAbWbLyUalNtfhQM%Fp}^T@xdbFP zvrc5+wv(8>BF#R1^tqhHMcVaik9R#FAb0Yd6Cd^{&|p>ug>)y~*aNaAR+7@0NZ-lg zuY2ClWFX`q&6)yWW#69jM-KVVVI3dc9n1 zGH6Nqm~)97>uT$D%q0+da=L9gYScPF$`%dOq#K!w)E$Gnp#Bh;n@hDF zIxca5++i-Y)Y|Q#Z-4ObM)Jv+f5=0AC60c}$+lXA8^|`7h_3nHeImgqs6PbEyDmCH zFwKEwmrWbmLrBebdtxqIM1p@11XAN76WPNWw`iay-DsIfS$l$@Ql|J|ZQt|Bfx7!$tgpEo--nYOgTtWy5SW?ElXlp- zJQ)2^Hvsni4w#`^&sK-bU&37F=_)zoCSD z2IIjjs6Pb0Z7v6UY$8t?!OL9Atgqtybz@`<1jhS)wpE&gVAjnlI{;vzeE+*DdiI0J zH}i=ALH!{x-W_Y&X!0($8SX2*jBM2%W=PowWI78x?1TD4z`o~Kj6x1lps`2XYr@H1 z!U60uc#KWRHFeO=QuhIU*#th;H>sddNj` z?Xz>1BIlr<5uklW1*e=@v1*Tw({VQ)Cndy~46$`O=98yky&ZW(1j)r*>bvMyI@m`j zbkM9Bp$jW}Ome;ZI`rmsGL)dx>k5Q#s~1`Og}XSh`e;!>4nh4PFuLc925Qm`@Ey(i z*bb7Gu8T18Spr>(j?c2$T-us~_k+Obo=*-G8t(Fu4tz$VueXE8mVSR`fQ&Mc9J1B2 zgicU@2=w+G9njttZMrB?YX~V@klvx9nJH3>}D$m0zv&DF#5T?XrLCk0p4Ss z3#;CJtCaOWF?yIm(=M}r3XN5VOt_L*`9q-BN2sFL4{Hai7eR{-nZ2ibn$nBLagW!T z_ArB{U8ZGLN9*Y!nl9tYV&x5i$qpDbJ7}a)H$XS+EJ#2ns6PZIJABft`GrEmu5tQo zUZ(5u*Nl-d5ZE?dFs2*TMFTbIX1Y@+tEG52@~`7GtPw%polaMaP(l46Fxjb-10@@7 zjgz~1!PMMtF3~>IlPGr+?t=P5K<=cK8*Lo4wClOV=8hKsZFUG8)E@%YNtCD3n%0y) zgX=#*%TRI#2Y!N1@(u3eU~fE$$^Ty zSnEVpSf}MI=dT+hV<0fI=Ub-?wAjH1{HU8M<(aJ4e3*Fh0>Fa$Ltv)E*9?@W4xd43 zVSQ+;LEvE))E@!^$6hIJusse!O!n=X;E(I2x!K=P0`h}d!z`#j1P+Eq>ww9DY8p<9 z5Hd8yQJ@DKVFfg!h$wz&1^kJ80I7Lc<=G_*tkKyI6TcV06#TqrgD)LQJ}W)1J#`kTstlmy%|y1tLNHAuzh< zR}Pds2!8Orsr}?0-64NH7#Z&oINNo$*fhbOnehidH6ZL_F3lfofY1)L)MUtGg(AIaxca2`|+l!N+1V6Y!hpxvz7{IhPx?d*v@pC-@> z>JNdzZbX5DX5|C@GNsqLnGNsJZZ>CN9Mm5I_B~%TP>bB;yczAf3R*+@c$~~ya>!cV zV${`1iO#X_Sb0OhzUK=EsU#9q(=^$4th^zh?W-bF zMBQI}U`(1O8+8M8!_I;Pbb|UrV6wv}&6=5Q*fma{&C7H>{+cl|1_Ilr3#L4^Y5lNh zpeEgDnR%A=Zz`rM!nOwWhrqV!NZZ~4lLHlZv8GQw`#z|e*w&!_5SW`wwH-Px`v<|A z;SMiHv+l1OBV!=Y86qL-@A>Fl_FcwA_0g5M%@HzndT-9?Romr zV<>_B}sq2%A%TywDuqqiPRe9Mlg2)%KaY->i6<--FQ~ zbpuet&WHrmg8D-sH93+t_q$n9Jy%uXnh?+8Wq5}OTbKp)hrsw$Hoxnb9}bMC+ecYdld-hpv{-tS$($uFQfB8E$yj+q zz`o0yCYP64JIA_Lxk13qNeTaaT+AhQ`lr&to@SV`;Vf4S2c!Q;yIG8Qb7JKWfwA$L z7!3K*Puzr?!8|7;@JG$;H0s_ENm2=!!`9t8WSGc0BKfum5i`hwU zoDuw7X6xLmiYWbm=EairnU9%zIBu-GAu!kvC{Hu%4NcQlvu-SQT53N_2DF0uLtwB| zQJ`kln@iY{%zV-`;D4FPS>d;M-|2+gUG31;9=iF%na^4Y6zZWb45#~8%Q8v=4C&74{B zGHg63!cs5;a~XE%GYtvo1oel2wy%mz5e`Z|)8? z0Ft2o5ZKxgX`6e~tazE392{cScB#38RpmO0MG1B1%JWXI31*r)KY2bFy}r1@(tO z85?^SUp1EnA$z>g1ZaCCAdyd~Eyr51a)N*|ms~;ahr;cfgN2%`X%kp`E%_3zzrzN6PJ>w9(=kgh3yb~J|my$G8bR-y)Sb0Mr?>gsv#uZhq zSx#m4c%ey?$9r@NZrLKnE>_+Uun9%&av)QZV+&DQo=t2r=5GV^#QG*{ty`4 zb1pC&&T_?YF#37V|l`VFZkoi_=B#-rCw7# zeZ5?lM2Rbnl{W4+P4`JAg7 z`x=*e9dr4dd%vq{+jM@n?hW-2JZqL?mn?~uK!88I&cM|)*=6+s%WuZY2LfU)_x->{ za4+zC##L=vuZ`wEMUA1^?}J^&XvJJI7VcK}m`it{d{4p$vv;yX2Uhtp{(H)ZsMjO# F{{a9$T9^O; literal 0 HcmV?d00001 diff --git a/examples/hotplug_sensor_examples/images/BGimage4.bmp.license b/examples/hotplug_sensor_examples/images/BGimage4.bmp.license new file mode 100644 index 0000000..82d4370 --- /dev/null +++ b/examples/hotplug_sensor_examples/images/BGimage4.bmp.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2022 PaulskPt +# SPDX-License-Identifier: MIT From 9a7095105413914769ac0d89a4f6a942ab64c667 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 15 May 2022 12:49:40 -0400 Subject: [PATCH 067/132] Patch .pre-commit-config.yaml --- .pre-commit-config.yaml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 29230db..0a91a11 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,40 +3,40 @@ # SPDX-License-Identifier: Unlicense repos: -- repo: https://github.com/python/black + - repo: https://github.com/python/black rev: 22.3.0 hooks: - - id: black -- repo: https://github.com/fsfe/reuse-tool - rev: v0.12.1 + - id: black + - repo: https://github.com/fsfe/reuse-tool + rev: v0.14.0 hooks: - - id: reuse -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.3.0 + - id: reuse + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 hooks: - - id: check-yaml - - id: end-of-file-fixer - - id: trailing-whitespace -- repo: https://github.com/pycqa/pylint + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/pycqa/pylint rev: v2.11.1 hooks: - - id: pylint + - id: pylint name: pylint (library code) types: [python] args: - --disable=consider-using-f-string,duplicate-code exclude: "^(docs/|examples/|tests/|setup.py$)" - - id: pylint + - id: pylint name: pylint (example code) description: Run pylint rules on "examples/*.py" files types: [python] files: "^examples/" args: - - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code - - id: pylint + - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code + - id: pylint name: pylint (test code) description: Run pylint rules on "tests/*.py" files types: [python] files: "^tests/" args: - - --disable=missing-docstring,consider-using-f-string,duplicate-code + - --disable=missing-docstring,consider-using-f-string,duplicate-code From d52bbdfa134397376b82ccb23f7721b39f02b8a8 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Sun, 15 May 2022 21:55:05 +0100 Subject: [PATCH 068/132] various mods in 2nd test script idem --- ...or_datetime_fm_NTP_touch_and_gVars_test.py | 120 +++++++++--------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py index 65b122c..4f8d9b1 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py @@ -2,16 +2,14 @@ # # SPDX-License-Identifier: MIT """ -Notes by @PaulskPt: tested on an Adafruit PyPortal Titano +Notes by @PaulskPt +Script tested on an Adafruit PyPortal Titano (Product ID 4444. See: https://www.adafruit.com/product/4444) This script can make use of an I2C Realtime Clock type DS3231 -When the flag 'use_ntp' is set, the DS3231 will not be used, +However, when the flag 'use_ntp' is set, the DS3231 will not be used instead the NTP class from adafruit_ntp.py will be used. """ - import time - -# import gc import board import busio import displayio @@ -31,6 +29,7 @@ from adafruit_bitmap_font import bitmap_font from adafruit_displayio_layout.layouts.tab_layout import TabLayout + # +-------------------------------------------------------+ # | Definition for variables in the past defined as global| # +-------------------------------------------------------+ @@ -233,18 +232,6 @@ def list(self): spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -# ---------- Text Boxes ------------- # -# Set the font and preload letters -font_arial = bitmap_font.load_font( - "/fonts/Arial-16.bdf" -) # was: Helvetica-Bold-16.bdf") -# font.load_glyphs(b"abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()") -glyphs = b' "(),-.0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' -font_arial.load_glyphs(glyphs) -font_arial.load_glyphs(("°",)) # a non-ascii character we need -# gc.collect() # ADDED by @PaulskPt -- to prevent MemoryError - memory allocation failed, -# allocating 6444 bytes - # ------------- Screen Setup ------------- # pyportal = None timeout_cnt = 0 @@ -367,8 +354,10 @@ def refresh_from_NTP(): if timeout_cnt2 > 10: print("Timeout while trying to get ntp datetime to set the internal rtc") break + if myVars.read("my_debug"): print("Value ntp.valid_time = ", ntp.valid_time) + if ntp.valid_time: myVars.write("online_time_present", True) myVars.write("ntp_refresh", False) @@ -377,6 +366,7 @@ def refresh_from_NTP(): ntp_current_time = time.time() if myVars.read("my_debug"): print("Seconds since Jan 1, 1970: {} seconds".format(ntp_current_time)) + # Convert the current time in seconds since Jan 1, 1970 to a struct_time myVars.write("default_dt", time.localtime(ntp_current_time)) if not myVars.read("my_debug"): @@ -463,8 +453,8 @@ def refresh_from_NTP(): display.show(main_group) # font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") -# font = bitmap_font.load_font("/fonts/Arial-16.bdf") -font = terminalio.FONT +font_arial = bitmap_font.load_font("/fonts/Arial-16.bdf") +font_term = terminalio.FONT # create the page layout test_page_layout = TabLayout( @@ -472,7 +462,7 @@ def refresh_from_NTP(): y=0, display=board.DISPLAY, tab_text_scale=2, - custom_font=font, + custom_font=font_term, inactive_tab_spritesheet="lib/adafruit_displayio_layout/examples/bmps/inactive_tab_sprite.bmp", showing_tab_spritesheet="lib/adafruit_displayio_layout/examples/bmps/active_tab_sprite.bmp", showing_tab_text_color=0x00AA59, @@ -501,34 +491,29 @@ def set_image(group, filename): :param filename: The filename of the chosen image """ print("Set image to ", filename) + image = None + image_sprite = None if group: group.pop() if not filename: return # we're done, no icon desired # CircuitPython 6 & 7 compatible - image_file = None try: - # image_file = open(filename, "rb") - with open(filename, "rb") as image_file: - image = displayio.OnDiskBitmap(image_file) + image = displayio.OnDiskBitmap(filename) except OSError as exc: if exc.args[0] == 2: # No such file/directory return - finally: - if image_file is not None: - image_file.close() - - image_sprite = displayio.TileGrid( - image, pixel_shader=getattr(image, "pixel_shader", displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # image = displayio.OnDiskBitmap(filename) - # image_sprite = displayio.TileGrid(image, pixel_shader=image.pixel_shader) - main_group.append(image_sprite) + if image is not None: + image_sprite = displayio.TileGrid( + image, + pixel_shader=getattr(image, "pixel_shader", displayio.ColorConverter()), + ) + if image_sprite is not None: + main_group.append(image_sprite) # ------------- Setup for Images ------------- # + bg_group = displayio.Group() set_image(bg_group, "/images/BGimage4.bmp") print( @@ -544,71 +529,70 @@ def set_image(group, filename): # labels pge1_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="This is the first page!", anchor_point=(0, 0), anchored_position=(10, 10), ) pge1_lbl2 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="Please wait...", anchor_point=(0, 0), anchored_position=(10, 150), ) pge2_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="This page is the second page!", anchor_point=(0, 0), anchored_position=(10, 10), ) pge3_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text=myVars.read("pge3_lbl_dflt"), # Will be "Date/time:" anchor_point=(0, 0), anchored_position=(10, 10), ) pge3_lbl2 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # pge3_lbl2_dflt, # Will be DD-MO-YYYY or Month-DD-YYYY anchor_point=(0, 0), anchored_position=(10, 40), ) pge3_lbl3 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # pge3_lbl3_dflt, # Will be HH:MM:SS anchor_point=(0, 0), anchored_position=(10, 70), ) pge3_lbl4 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # pge3_lbl3_dflt, # Will be time until next NTP sync in MM:SS anchor_point=(0, 0), anchored_position=(10, 200), ) pge4_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text=myVars.read("pge4_lbl_dflt"), anchor_point=(0, 0), anchored_position=(10, 10), ) pge4_lbl2 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # Will be "Temperature" anchor_point=(0, 0), anchored_position=(10, 130), ) - pge4_lbl3 = Label( - font=font_arial, + font=font_arial, # bitmap_font.load_font("/fonts/Arial-16.bdf"), scale=2, text="", # Will be "xx.yy ºC" anchor_point=(0, 0), @@ -620,6 +604,7 @@ def set_image(group, filename): circle = Circle(50, 100, r=30, fill=0xDD00DD) triangle = Triangle(50, 0, 100, 50, 0, 50, fill=0xDDDD00) rectangle = Rect(x=80, y=60, width=100, height=50, fill=0x0000DD) + triangle.x = 80 triangle.y = 70 @@ -653,12 +638,24 @@ def set_image(group, filename): # add it to the group that is showing on the display main_group.append(test_page_layout) # test_page_layout.tab_tilegrids_group[3].x += 50 +# ---------- Text Boxes ------------- # +# Set the font and preload letters +# font = bitmap_font.load_font("/fonts/Arial-16.bdf") # was: Helvetica-Bold-16.bdf") +# font.load_glyphs(b"abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()") +glyphs = b' "(),-.0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +font_arial.load_glyphs(glyphs) +font_arial.load_glyphs(("°",)) # a non-ascii character we need +# gc.collect() # ADDED by @PaulskPt -- to prevent MemoryError - memory allocation failed, +# allocating 6444 bytes + pge2_group = 1 -"""If the temperature sensor has been disconnected, +""" + If the temperature sensor has been disconnected, this function will try to reconnect (test if the sensor is present by now) - If reconnected this function creates the temp_sensor object""" + If reconnected this function creates the temp_sensor object +""" def connect_temp_sensor(): @@ -689,8 +686,10 @@ def connect_temp_sensor(): myVars.write("t2", None) -"""If the external rtc has been disconnected, - this function will try to reconnect (test if the external rtc is present by now)""" +""" + If the external rtc has been disconnected, + this function will try to reconnect (test if the external rtc is present by now) +""" def connect_rtc(): @@ -716,12 +715,14 @@ def connect_rtc(): print("Failed to connect RTC") -"""Function gets a value from the external temperature sensor +""" + Function gets a value from the external temperature sensor It only updates if the value has changed compared to the previous value A fixed text is set in pge4_lbl2.text. The variable temperature value is set in pge4_lbl3.text If no value obtained (for instance if the sensor is disconnected), the function sets the pge4_lbl to a default text and makes empty - pge4_lbl2.text and pge4_lbl3.text""" + pge4_lbl2.text and pge4_lbl3.text +""" def get_temp(): @@ -761,7 +762,6 @@ def get_temp(): ) # clean the line (eventually: t2) pge4_lbl2.text = "Sensor disconnected." pge4_lbl3.text = "Check wiring." - return RetVal @@ -843,11 +843,14 @@ def handle_dt(dt): return RetVal -""" Function gets the date and time: a) if an rtc is present from the rtc; +""" + Function gets the date and time: + a) if an rtc is present from the rtc; b) if using online NTP pool server then get the date and time from the function time.localtime This time.localtime has before been set with data from the NTP server. In both cases the date and time will be set to the pge3_lbl, pge3_lbl12 and pge3_lbl3 - If no (valid) datetime a default text will be shown on the pge3_lbl""" + If no (valid) date and time has been received then a default text will be shown on the pge3_lbl +""" def get_dt(): @@ -905,16 +908,13 @@ def ck_next_NTP_sync(): c_elapsed = c_cnt - s_cnt if c_elapsed < 10: # continue only when c_elapsed >= 10 return - TAG = "ck_next_NTP_sync(): " my_debug = myVars.read("my_debug") t1 = myVars.read("next_NTP_sync_t1") t3 = myVars.read("next_NTP_sync_t3") five_min = myVars.read("five_min_cnt") myVars.write("s_cnt", hms_to_cnt()) - # --- five minutes count down calculations #1 --- - if my_debug: print( TAG + "five_min = {}, s_cnt = {}, c_cnt = {}".format(five_min, s_cnt, c_cnt) @@ -958,7 +958,6 @@ def main(): while True: touch = ts.touch_point try: - if use_ntp: ck_next_NTP_sync() ntp_refresh = myVars.read("ntp_refresh") @@ -986,7 +985,6 @@ def main(): # the touch data has lost if myVars.read("temp_in_REPL"): myVars.write("temp_in_REPL", False) - cnt = inc_cnt(cnt) except KeyboardInterrupt as exc: print("Keyboard interrupt...exiting...") From 417c80acdb5e1d094ffbdfd897e96dc43572c039 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Mon, 16 May 2022 14:11:39 +0100 Subject: [PATCH 069/132] second example added flag "temp_in_fahrenheit" In gVars class added flag "temp_in_fahrenheit". In second example modified algorithm to display the temperature sensor value in degrees Celsius or in degrees Fahrenheit depending the flag. See lines 211 , 667-670 and 725-726. --- ...or_datetime_fm_NTP_touch_and_gVars_test.py | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py index 4f8d9b1..a4a3301 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py @@ -69,6 +69,7 @@ def __init__(self): 25: "five_min_cnt", 26: "next_NTP_sync_t1", 27: "next_NTP_sync_t3", + 28: "temp_in_fahrenheit", } self.gVars_rDict = { @@ -100,6 +101,7 @@ def __init__(self): "five_min_cnt": 25, "next_NTP_sync_t1": 26, "next_NTP_sync_t3": 27, + "temp_in_fahrenheit": 28, } self.g_vars = {} @@ -161,6 +163,7 @@ def clean(self): 25: None, 26: None, 27: None, + 28: None, } def list(self): @@ -213,6 +216,7 @@ def list(self): myVars.write("five_min_cnt", 0) myVars.write("next_NTP_sync_t1", "Next NTP sync in ") myVars.write("next_NTP_sync_t3", " (mm:ss)") +myVars.write("temp_in_fahrenheit", True) # nHH_old is used to check if the hour has changed. # If so we have to re-sync from NTP server # (if not using an external RTC) @@ -645,17 +649,16 @@ def set_image(group, filename): glyphs = b' "(),-.0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' font_arial.load_glyphs(glyphs) font_arial.load_glyphs(("°",)) # a non-ascii character we need -# gc.collect() # ADDED by @PaulskPt -- to prevent MemoryError - memory allocation failed, +# font=font_term.collect() # ADDED by @PaulskPt -- +# to prevent MemoryError - memory allocation failed, # allocating 6444 bytes pge2_group = 1 -""" - If the temperature sensor has been disconnected, +"""If the temperature sensor has been disconnected, this function will try to reconnect (test if the sensor is present by now) - If reconnected this function creates the temp_sensor object -""" + If reconnected this function creates the temp_sensor object""" def connect_temp_sensor(): @@ -676,7 +679,10 @@ def connect_temp_sensor(): print(t) print("temperature sensor connected") myVars.write("t0", "Temperature") - myVars.write("t1", chr(186) + "C") + if myVars.read("temp_in_fahrenheit"): + myVars.write("t1", chr(186) + "F") + else: + myVars.write("t1", chr(186) + "C") myVars.write("t2", 27 * "_") else: print("no " + t) @@ -686,10 +692,8 @@ def connect_temp_sensor(): myVars.write("t2", None) -""" - If the external rtc has been disconnected, - this function will try to reconnect (test if the external rtc is present by now) -""" +""" If the external rtc has been disconnected, + this function will try to reconnect (test if the external rtc is present by now)""" def connect_rtc(): @@ -715,14 +719,12 @@ def connect_rtc(): print("Failed to connect RTC") -""" - Function gets a value from the external temperature sensor +"""Function gets a value from the external temperature sensor It only updates if the value has changed compared to the previous value A fixed text is set in pge4_lbl2.text. The variable temperature value is set in pge4_lbl3.text If no value obtained (for instance if the sensor is disconnected), the function sets the pge4_lbl to a default text and makes empty - pge4_lbl2.text and pge4_lbl3.text -""" + pge4_lbl2.text and pge4_lbl3.text""" def get_temp(): @@ -732,6 +734,8 @@ def get_temp(): if myVars.read("temp_sensor") is not None: try: temp = myVars.read("temp_sensor").temperature + if myVars.read("temp_in_fahrenheit"): + temp = (temp * 1.8) + 32 t = "{:5.2f}{} ".format(temp, myVars.read("t1")) if my_debug and temp is not None and not myVars.read("temp_in_REPL"): myVars.write("temp_in_REPL", True) @@ -767,7 +771,6 @@ def get_temp(): # Moved these six definitions outside handle_dt() # to correct pylint error 'too many variables' -# dt_idxs = {0: "yy", 1:"mo", 2:"dd", 3:"hh", 4:"mm", 5:"ss"} dt_ridxs = {"yy": 0, "mo": 1, "dd": 2, "hh": 3, "mm": 4, "ss": 5} # print("dict dt_ridxs =", dt_ridxs.keys()) @@ -843,14 +846,12 @@ def handle_dt(dt): return RetVal -""" - Function gets the date and time: +"""Function gets the date and time: a) if an rtc is present from the rtc; b) if using online NTP pool server then get the date and time from the function time.localtime This time.localtime has before been set with data from the NTP server. In both cases the date and time will be set to the pge3_lbl, pge3_lbl12 and pge3_lbl3 - If no (valid) date and time has been received then a default text will be shown on the pge3_lbl -""" + If no (valid) date and time received then a default text will be shown on the pge3_lbl""" def get_dt(): From ceb426bf80e5e6120585801239272667caeaf506 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Mon, 16 May 2022 14:29:17 +0100 Subject: [PATCH 070/132] first example added flag "temp_in_fahrenheit" As just done with the second example. Added possibility to switch temperature displayed in degrees Celsius or degrees Fahrenheit by setting the gVars flag variable "temp_in_fahrenheit" --- ...layout_hotplug_ext_rtc_temp_sensor_test.py | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index 97dd031..f97d2c6 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -15,6 +15,7 @@ from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle from adafruit_display_shapes.triangle import Triangle +from adafruit_bitmap_font import bitmap_font from adafruit_displayio_layout.layouts.tab_layout import TabLayout # +-------------------------------------------------------+ @@ -49,6 +50,7 @@ def __init__(self): 18: "use_txt_in_month", 19: "use_usa_notation", 20: "content_sensor_idx", + 21: "temp_in_fahrenheit", } self.gVars_rDict = { @@ -73,6 +75,7 @@ def __init__(self): "use_txt_in_month": 18, "use_usa_notation": 19, "content_sensor_idx": 20, + "temp_in_fahrenheit": 21, } self.g_vars = {} @@ -127,6 +130,7 @@ def clean(self): 18: None, 19: None, 20: None, + 21: None, } def list(self): @@ -203,6 +207,7 @@ def list(self): myVars.write("use_usa_notation", True) myVars.write("use_ntp", False) myVars.write("content_sensor_idx", None) +myVars.write("temp_in_fahrenheit", True) # ------------------------------------------------------------------------- if myVars.read("my_debug"): # print list of all variables in myVars @@ -221,7 +226,8 @@ def list(self): display.show(main_group) # fon.gvars bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") -font = terminalio.FONT +font_arial = bitmap_font.load_font("/fonts/Arial-16.bdf") +font_term = terminalio.FONT # create the page layout test_page_layout = TabLayout( @@ -229,7 +235,7 @@ def list(self): y=0, display=board.DISPLAY, tab_text_scale=2, - custom_font=font, + custom_font=font_term, inactive_tab_spritesheet="bmps/inactive_tab_sprite.bmp", showing_tab_spritesheet="bmps/active_tab_sprite.bmp", showing_tab_text_color=0x00AA59, @@ -247,63 +253,63 @@ def list(self): # labels pge1_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="This is the first page!", anchor_point=(0, 0), anchored_position=(10, 10), ) pge1_lbl2 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="Please wait...", anchor_point=(0, 0), anchored_position=(10, 150), ) pge2_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="This page is the second page!", anchor_point=(0, 0), anchored_position=(10, 10), ) pge3_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text=myVars.read("pge3_lbl_dflt"), # Will be "Date/time:" anchor_point=(0, 0), anchored_position=(10, 10), ) pge3_lbl2 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # pge3_lbl2_dflt, # Will be DD-MO-YYYY or Month-DD-YYYY anchor_point=(0, 0), anchored_position=(10, 40), ) pge3_lbl3 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # pge3_lbl3_dflt, # Will be HH:MM:SS anchor_point=(0, 0), anchored_position=(10, 70), ) pge4_lbl = Label( - font=terminalio.FONT, + font=font_term, scale=2, text=myVars.read("pge4_lbl_dflt"), anchor_point=(0, 0), anchored_position=(10, 10), ) pge4_lbl2 = Label( - font=terminalio.FONT, + font=font_term, scale=2, text="", # Will be "Temperature" anchor_point=(0, 0), anchored_position=(10, 130), ) pge4_lbl3 = Label( - font=terminalio.FONT, + font=font_arial, scale=2, text="", # Will be "xx.yy C" anchor_point=(0, 0), @@ -405,7 +411,11 @@ def connect_temp_sensor(): print(t) print("temperature sensor connected") myVars.write("t0", "Temperature") - myVars.write("t1", " C") + if myVars.read("temp_in_fahrenheit"): + myVars.write("t1", chr(186) + "F") + else: + myVars.write("t1", chr(186) + "C") + myVars.write("t2", 27 * "_") else: print("no " + t) @@ -460,6 +470,8 @@ def get_temp(): if myVars.read("temp_sensor") is not None: try: temp = myVars.read("temp_sensor").temperature + if myVars.read("temp_in_fahrenheit"): + temp = (temp * 1.8) + 32 t = "{:5.2f} ".format(temp) + myVars.read("t1") if ( myVars.read("my_debug") From 65a3d72dd6b2f6979e716be2a37e9bddc0561118 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Mon, 16 May 2022 14:38:11 +0100 Subject: [PATCH 071/132] example nr 1 changed temp readout to Celsius Now example #1 displays the temperature in degrees Celsius while example #2 displays the temperature in degrees Fahrenheit. --- ...playio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py index f97d2c6..f56413f 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py +++ b/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py @@ -207,7 +207,7 @@ def list(self): myVars.write("use_usa_notation", True) myVars.write("use_ntp", False) myVars.write("content_sensor_idx", None) -myVars.write("temp_in_fahrenheit", True) +myVars.write("temp_in_fahrenheit", False) # ------------------------------------------------------------------------- if myVars.read("my_debug"): # print list of all variables in myVars From b495a549698d6b641c6dfc42ef7cf674f82439b0 Mon Sep 17 00:00:00 2001 From: "Paulus H.J. Schulinck" Date: Mon, 16 May 2022 23:32:42 +0100 Subject: [PATCH 072/132] Aded the Arial-16 font Added the Arial-16.bdf font and it's license file --- examples/fonts/Arial-16.bdf | 7366 +++++++++++++++++++++++++++ examples/fonts/Arial-16.bdf.license | 3 + 2 files changed, 7369 insertions(+) create mode 100644 examples/fonts/Arial-16.bdf create mode 100644 examples/fonts/Arial-16.bdf.license diff --git a/examples/fonts/Arial-16.bdf b/examples/fonts/Arial-16.bdf new file mode 100644 index 0000000..087da7d --- /dev/null +++ b/examples/fonts/Arial-16.bdf @@ -0,0 +1,7366 @@ +STARTFONT 2.1 +COMMENT +COMMENT Converted from OpenType font "arial.ttf" by "otf2bdf 3.0". +COMMENT +FONT -FreeType-Arial-Medium-R-Normal--22-160-100-100-P-109-ISO10646-1 +SIZE 16 100 100 +FONTBOUNDINGBOX 43 29 -11 -7 +STARTPROPERTIES 19 +FOUNDRY "FreeType" +FAMILY_NAME "Arial" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 22 +POINT_SIZE 160 +RESOLUTION_X 100 +RESOLUTION_Y 100 +SPACING "P" +AVERAGE_WIDTH 109 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 19 +FONT_DESCENT 4 +COPYRIGHT " 2017 The Monotype Corporation. All Rights Reserved. Hebrew OpenType Layout logic copyright 2003 & 2007, Ralph Hancock & John Hudson. This layout logic for Biblical Hebrew is open source software under the MIT License; see embedded license description for details." +_OTF_FONTFILE "arial.ttf" +_OTF_PSNAME "ArialMT" +ENDPROPERTIES +CHARS 3361 +STARTCHAR 0020 +ENCODING 32 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 16 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 360 0 +DWIDTH 8 0 +BBX 6 6 1 10 +BITMAP +CC +CC +CC +CC +CC +CC +ENDCHAR +STARTCHAR 0023 +ENCODING 35 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 12 16 0 0 +BITMAP +0C60 +0C60 +0C60 +18C0 +FFF0 +FFF0 +18C0 +18C0 +3180 +3180 +FFF0 +FFF0 +3180 +6300 +6300 +6300 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 19 1 -2 +BITMAP +0800 +3E00 +7F80 +E9C0 +C8C0 +C800 +E800 +7800 +3F00 +0F80 +09C0 +08C0 +C8C0 +C8C0 +6980 +7F80 +3E00 +0800 +0800 +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 900 0 +DWIDTH 20 0 +BBX 18 16 1 0 +BITMAP +380600 +6C0C00 +C60C00 +C61800 +C63000 +C63000 +C66000 +6C6700 +38CD80 +0198C0 +0198C0 +0318C0 +0318C0 +0618C0 +0C0D80 +0C0700 +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 16 1 0 +BITMAP +0E00 +1F00 +3180 +3180 +3180 +1B00 +1F00 +1C00 +7600 +6330 +C1B0 +C1E0 +C0E0 +61A0 +7F98 +1E10 +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 2 6 1 10 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 5 20 1 -4 +BITMAP +08 +10 +30 +20 +60 +60 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +60 +60 +20 +30 +10 +08 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 5 20 1 -4 +BITMAP +80 +40 +60 +20 +30 +30 +18 +18 +18 +18 +18 +18 +18 +18 +30 +30 +20 +60 +40 +80 +ENDCHAR +STARTCHAR 002A +ENCODING 42 +SWIDTH 405 0 +DWIDTH 9 0 +BBX 8 7 1 9 +BITMAP +18 +18 +FF +3C +3C +66 +24 +ENDCHAR +STARTCHAR 002B +ENCODING 43 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 10 10 1 3 +BITMAP +0C00 +0C00 +0C00 +0C00 +FFC0 +FFC0 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 002C +ENCODING 44 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 5 2 -3 +BITMAP +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 002D +ENCODING 45 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 2 0 5 +BITMAP +FC +FC +ENDCHAR +STARTCHAR 002E +ENCODING 46 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 2 2 0 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 002F +ENCODING 47 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 7 16 0 0 +BITMAP +06 +06 +0C +0C +0C +18 +18 +18 +30 +30 +30 +60 +60 +60 +E0 +C0 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1E00 +3F80 +6180 +6180 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +6180 +6180 +3F00 +1E00 +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 6 16 2 0 +BITMAP +0C +0C +1C +7C +EC +8C +0C +0C +0C +0C +0C +0C +0C +0C +0C +0C +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +3F00 +7F80 +E1C0 +C0C0 +00C0 +00C0 +00C0 +0180 +0300 +0600 +0C00 +1800 +3000 +6000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +0180 +0300 +0E00 +0F00 +0180 +00C0 +00C0 +00C0 +C0C0 +E180 +7F80 +3E00 +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +0300 +0700 +0F00 +0F00 +1B00 +1B00 +3300 +7300 +6300 +C300 +FFC0 +FFC0 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +3F80 +3F80 +6000 +6000 +6000 +7E00 +FF80 +C180 +00C0 +00C0 +00C0 +00C0 +C0C0 +E180 +7F80 +3E00 +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1F00 +3F80 +61C0 +60C0 +C000 +C000 +CF00 +FF80 +E1C0 +C0C0 +C0C0 +C0C0 +C0C0 +6180 +7F80 +1E00 +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +FFC0 +FFC0 +0080 +0180 +0300 +0600 +0600 +0C00 +0C00 +1800 +1800 +1800 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1E00 +3F00 +6180 +6180 +6180 +6180 +3F00 +3F00 +6180 +C0C0 +C0C0 +C0C0 +C0C0 +6180 +7F80 +1E00 +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1E00 +7F00 +6180 +C080 +C0C0 +C0C0 +C0C0 +E1C0 +7FC0 +3CC0 +00C0 +00C0 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 003A +ENCODING 58 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 12 2 0 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 003B +ENCODING 59 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 15 2 -3 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +00 +00 +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 003C +ENCODING 60 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 11 1 2 +BITMAP +0020 +00E0 +07C0 +1E00 +7800 +C000 +7800 +1E00 +07C0 +00E0 +0020 +ENDCHAR +STARTCHAR 003D +ENCODING 61 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 7 1 4 +BITMAP +FFE0 +FFE0 +0000 +0000 +0000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 003E +ENCODING 62 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 11 1 2 +BITMAP +8000 +E000 +7C00 +0F00 +03C0 +0060 +03C0 +0F00 +7C00 +E000 +8000 +ENDCHAR +STARTCHAR 003F +ENCODING 63 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +3F00 +7F80 +E1C0 +C0C0 +00C0 +01C0 +0380 +0700 +0600 +0C00 +0C00 +0C00 +0000 +0000 +0C00 +0C00 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 990 0 +DWIDTH 22 0 +BBX 20 21 1 -5 +BITMAP +01F800 +07FE00 +1E0780 +180180 +31CCC0 +77ECE0 +6E3860 +6C1860 +DC1860 +D81860 +D81860 +D830C0 +D831C0 +DC7380 +EFFF00 +671C00 +700030 +3800E0 +1E03C0 +0FFF80 +01FC00 +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 16 0 0 +BITMAP +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 16 2 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FFC0 +C060 +C030 +C030 +C030 +C070 +FFE0 +FF80 +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 16 1 0 +BITMAP +07C0 +1FF0 +3838 +6018 +600C +C000 +C000 +C000 +C000 +C000 +C000 +600C +6018 +3838 +1FF0 +0FC0 +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 13 16 2 0 +BITMAP +FF80 +FFE0 +C070 +C030 +C038 +C018 +C018 +C018 +C018 +C018 +C018 +C030 +C030 +C0E0 +FFE0 +FF80 +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 16 2 0 +BITMAP +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 10 16 2 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 16 1 0 +BITMAP +07E0 +1FF8 +381C +700C +6006 +C000 +C000 +C000 +C0FE +C0FE +C006 +6006 +7006 +381E +1FFC +07E0 +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 16 2 0 +BITMAP +C030 +C030 +C030 +C030 +C030 +C030 +C030 +FFF0 +FFF0 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 16 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 004A +ENCODING 74 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 8 16 1 0 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +C3 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR 004B +ENCODING 75 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 16 2 0 +BITMAP +C070 +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +FE00 +E700 +C380 +C1C0 +C0C0 +C0E0 +C070 +C038 +ENDCHAR +STARTCHAR 004C +ENCODING 76 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 16 2 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 004D +ENCODING 77 +SWIDTH 855 0 +DWIDTH 19 0 +BBX 15 16 2 0 +BITMAP +E00E +F01E +F01E +F01E +D836 +D836 +D836 +CC66 +CC66 +CC66 +C6C6 +C6C6 +C6C6 +C386 +C386 +C386 +ENDCHAR +STARTCHAR 004E +ENCODING 78 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 16 2 0 +BITMAP +C030 +E030 +F030 +F030 +D830 +D830 +CC30 +C630 +C630 +C330 +C1B0 +C1B0 +C0F0 +C0F0 +C070 +C030 +ENDCHAR +STARTCHAR 004F +ENCODING 79 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 16 1 0 +BITMAP +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 16 2 0 +BITMAP +FF80 +FFE0 +C060 +C030 +C030 +C030 +C030 +C060 +FFE0 +FF80 +C000 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 17 1 -1 +BITMAP +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +70EC +3838 +1FF8 +07EE +0002 +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 16 2 0 +BITMAP +FFC0 +FFE0 +C070 +C030 +C030 +C030 +C070 +FFE0 +FFC0 +C300 +C180 +C1C0 +C0E0 +C060 +C070 +C030 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 16 1 0 +BITMAP +0FC0 +3FE0 +7070 +6018 +6018 +7000 +3C00 +1FC0 +03F0 +0038 +C018 +C018 +6018 +7070 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 12 16 1 0 +BITMAP +FFF0 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 16 2 0 +BITMAP +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 16 0 0 +BITMAP +C006 +E00E +600C +600C +3018 +3018 +3838 +1830 +1830 +0C60 +0C60 +0C60 +06C0 +06C0 +07C0 +0380 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 945 0 +DWIDTH 21 0 +BBX 21 16 0 0 +BITMAP +C07018 +C07018 +60D830 +60D830 +60D830 +60D830 +318C60 +318C60 +318C60 +318C60 +1B06C0 +1B06C0 +1B06C0 +1B06C0 +0E0380 +0E0380 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 16 0 0 +BITMAP +701C +3838 +1830 +0C60 +0EE0 +06C0 +0380 +0380 +0380 +06C0 +0C60 +1C70 +1830 +3018 +701C +E00E +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 14 16 0 0 +BITMAP +E01C +6018 +3030 +3870 +1860 +0CC0 +0FC0 +0780 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 005A +ENCODING 90 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 12 16 0 0 +BITMAP +7FF0 +7FF0 +0060 +00C0 +00C0 +0180 +0300 +0600 +0600 +0C00 +1800 +3000 +3000 +6000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 005B +ENCODING 91 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 4 20 1 -4 +BITMAP +F0 +F0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +F0 +F0 +ENDCHAR +STARTCHAR 005C +ENCODING 92 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 7 16 0 0 +BITMAP +C0 +C0 +60 +60 +60 +30 +30 +30 +18 +18 +18 +0C +0C +0C +0E +06 +ENDCHAR +STARTCHAR 005D +ENCODING 93 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 4 20 1 -4 +BITMAP +F0 +F0 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +F0 +ENDCHAR +STARTCHAR 005E +ENCODING 94 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 9 0 7 +BITMAP +0C00 +1E00 +1E00 +3300 +3300 +3300 +6180 +6180 +C0C0 +ENDCHAR +STARTCHAR 005F +ENCODING 95 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 12 2 0 -4 +BITMAP +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 3 3 1 13 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF80 +E180 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E180 +FF80 +DE00 +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +1E00 +7F00 +6380 +C180 +C000 +C000 +C000 +C000 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +00C0 +00C0 +00C0 +00C0 +1EC0 +7FC0 +61C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7FC0 +1EC0 +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 7 16 0 0 +BITMAP +1E +3E +30 +30 +FC +FC +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +1EC0 +7FC0 +61C0 +E0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +61C0 +7FC0 +1EC0 +00C0 +C180 +FF80 +3E00 +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 225 0 +DWIDTH 5 0 +BBX 2 16 1 0 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006A +ENCODING 106 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 4 20 -1 -4 +BITMAP +30 +30 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 006B +ENCODING 107 +SWIDTH 450 0 +DWIDTH 10 0 +BBX 9 16 1 0 +BITMAP +C000 +C000 +C000 +C000 +C380 +C700 +CE00 +DC00 +F800 +FC00 +EC00 +CE00 +C600 +C700 +C300 +C380 +ENDCHAR +STARTCHAR 006C +ENCODING 108 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 2 16 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006D +ENCODING 109 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 16 12 1 0 +BITMAP +DE3C +FF7E +E3C7 +C183 +C183 +C183 +C183 +C183 +C183 +C183 +C183 +C183 +ENDCHAR +STARTCHAR 006E +ENCODING 110 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 006F +ENCODING 111 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +DE00 +FF80 +E180 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E180 +FF00 +DE00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +1EC0 +7FC0 +61C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +61C0 +7FC0 +1EC0 +00C0 +00C0 +00C0 +00C0 +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 12 1 0 +BITMAP +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +3E00 +7F00 +C180 +C000 +F000 +7E00 +1F80 +0380 +0180 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 5 16 0 0 +BITMAP +20 +60 +60 +60 +F8 +F8 +60 +60 +60 +60 +60 +60 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 11 12 0 0 +BITMAP +C060 +C060 +60C0 +60C0 +3180 +3180 +3180 +1B00 +1B00 +0E00 +0E00 +0400 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 12 0 0 +BITMAP +C106 +C386 +C386 +628C +66CC +26C8 +36D8 +36D8 +1450 +1C70 +1C70 +0C60 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 450 0 +DWIDTH 10 0 +BBX 10 12 0 0 +BITMAP +E1C0 +6180 +3300 +3300 +1E00 +0C00 +0C00 +1E00 +3300 +3300 +6180 +E1C0 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 11 16 0 -4 +BITMAP +C060 +C060 +60C0 +60C0 +30C0 +3180 +1980 +1980 +0F00 +0F00 +0700 +0600 +0E00 +0C00 +7C00 +7800 +ENDCHAR +STARTCHAR 007A +ENCODING 122 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +7FC0 +7FC0 +01C0 +0380 +0700 +0E00 +1C00 +3800 +7000 +E000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 007B +ENCODING 123 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 20 0 -4 +BITMAP +1C +3C +30 +30 +30 +30 +30 +30 +60 +E0 +E0 +60 +30 +30 +30 +30 +30 +30 +3C +1C +ENDCHAR +STARTCHAR 007C +ENCODING 124 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 21 2 -5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 007D +ENCODING 125 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 20 1 -4 +BITMAP +E0 +F0 +30 +30 +30 +30 +30 +30 +38 +1C +1C +38 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 007E +ENCODING 126 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 4 1 6 +BITMAP +7800 +FE20 +8FE0 +03C0 +ENDCHAR +STARTCHAR 00A0 +ENCODING 160 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 00A1 +ENCODING 161 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 16 2 -4 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00A2 +ENCODING 162 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 20 1 -4 +BITMAP +0100 +0100 +0100 +0100 +1E00 +3F80 +6380 +E4C0 +C400 +C400 +C800 +C800 +E8C0 +7980 +3F80 +1E00 +1000 +2000 +2000 +2000 +ENDCHAR +STARTCHAR 00A3 +ENCODING 163 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 11 16 0 0 +BITMAP +1F00 +3F80 +71C0 +60C0 +6000 +6000 +6000 +FE00 +FE00 +3000 +3000 +3000 +6000 +7C40 +FFE0 +83C0 +ENDCHAR +STARTCHAR 00A4 +ENCODING 164 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 11 11 1 2 +BITMAP +4040 +EEE0 +7FC0 +3180 +60C0 +60C0 +60C0 +3180 +7FC0 +EEE0 +4040 +ENDCHAR +STARTCHAR 00A5 +ENCODING 165 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 12 16 0 0 +BITMAP +C030 +6060 +6060 +30C0 +30C0 +1980 +1F80 +0F00 +7FE0 +7FE0 +0600 +0600 +7FE0 +7FE0 +0600 +0600 +ENDCHAR +STARTCHAR 00A6 +ENCODING 166 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 21 2 -5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00A7 +ENCODING 167 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 20 1 -4 +BITMAP +1E00 +3F00 +7380 +6180 +6000 +3800 +7C00 +CE00 +C380 +C1C0 +E0C0 +70C0 +1D80 +0F00 +0700 +0180 +6180 +7180 +3F00 +1E00 +ENDCHAR +STARTCHAR 00A8 +ENCODING 168 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 2 1 14 +BITMAP +CC +CC +ENDCHAR +STARTCHAR 00A9 +ENCODING 169 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 16 16 0 0 +BITMAP +07E0 +1818 +2004 +43C2 +4422 +8811 +8801 +8801 +8801 +8801 +8811 +4422 +43C2 +2004 +1818 +07E0 +ENDCHAR +STARTCHAR 00AA +ENCODING 170 +SWIDTH 360 0 +DWIDTH 8 0 +BBX 7 8 0 8 +BITMAP +7C +C6 +06 +3E +F6 +C6 +CE +76 +ENDCHAR +STARTCHAR 00AB +ENCODING 171 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 10 1 1 +BITMAP +1980 +3300 +7700 +6600 +CC00 +CC00 +6600 +7700 +3300 +1980 +ENDCHAR +STARTCHAR 00AC +ENCODING 172 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 6 1 5 +BITMAP +FFE0 +FFE0 +0060 +0060 +0060 +0060 +ENDCHAR +STARTCHAR 00AD +ENCODING 173 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 2 0 5 +BITMAP +FC +FC +ENDCHAR +STARTCHAR 00AE +ENCODING 174 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 16 16 0 0 +BITMAP +07E0 +1818 +2004 +47C2 +4422 +8421 +8421 +87C1 +8481 +8441 +8421 +4422 +4412 +2004 +1818 +07E0 +ENDCHAR +STARTCHAR 00AF +ENCODING 175 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 13 2 -1 17 +BITMAP +FFF8 +FFF8 +ENDCHAR +STARTCHAR 00B0 +ENCODING 176 +SWIDTH 405 0 +DWIDTH 9 0 +BBX 6 6 1 10 +BITMAP +78 +CC +84 +84 +CC +78 +ENDCHAR +STARTCHAR 00B1 +ENCODING 177 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 13 1 0 +BITMAP +0C00 +0C00 +0C00 +0C00 +FFC0 +FFC0 +0C00 +0C00 +0C00 +0C00 +0000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 00B2 +ENCODING 178 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 7 8 0 8 +BITMAP +7C +C6 +06 +0E +1C +38 +60 +FE +ENDCHAR +STARTCHAR 00B3 +ENCODING 179 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 7 8 0 8 +BITMAP +7C +C6 +06 +18 +06 +06 +C6 +7C +ENDCHAR +STARTCHAR 00B4 +ENCODING 180 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 3 3 2 13 +BITMAP +60 +C0 +80 +ENDCHAR +STARTCHAR 00B5 +ENCODING 181 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +FFC0 +DEC0 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00B6 +ENCODING 182 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 12 20 0 -4 +BITMAP +3FF0 +7FF0 +FC60 +FC60 +FC60 +FC60 +FC60 +7C60 +3C60 +0C60 +0C60 +0C60 +0C60 +0C60 +0C60 +0C60 +0C60 +0C60 +0C60 +0C60 +ENDCHAR +STARTCHAR 00B7 +ENCODING 183 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 2 2 3 7 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 00B8 +ENCODING 184 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 5 4 1 -4 +BITMAP +20 +30 +18 +F0 +ENDCHAR +STARTCHAR 00B9 +ENCODING 185 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 4 8 1 8 +BITMAP +30 +70 +F0 +B0 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00BA +ENCODING 186 +SWIDTH 360 0 +DWIDTH 8 0 +BBX 8 8 0 8 +BITMAP +3C +66 +C3 +C3 +C3 +C3 +66 +3C +ENDCHAR +STARTCHAR 00BB +ENCODING 187 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 10 2 1 +BITMAP +CC00 +6600 +7700 +3300 +1980 +1980 +3300 +7700 +6600 +CC00 +ENDCHAR +STARTCHAR 00BC +ENCODING 188 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 16 16 2 0 +BITMAP +300C +7018 +F030 +B060 +3060 +30C0 +3180 +3300 +0306 +060E +0C1E +0C36 +1866 +307F +6006 +6006 +ENDCHAR +STARTCHAR 00BD +ENCODING 189 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 16 16 2 0 +BITMAP +300C +7018 +F030 +B060 +3060 +30C0 +3180 +3180 +031E +0633 +0C03 +0C07 +1806 +300C +7018 +603F +ENDCHAR +STARTCHAR 00BE +ENCODING 190 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 17 16 0 0 +BITMAP +7C0300 +C60600 +060C00 +180C00 +061800 +063000 +C63000 +7C6000 +00C300 +018700 +018F00 +031B00 +063300 +0C3F80 +0C0300 +180300 +ENDCHAR +STARTCHAR 00BF +ENCODING 191 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 9 16 2 -4 +BITMAP +0C00 +0C00 +0000 +0000 +0C00 +0C00 +0C00 +1800 +3800 +7000 +E000 +C000 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00C0 +ENCODING 192 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 0 +BITMAP +0300 +0180 +0080 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 00C1 +ENCODING 193 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 0 +BITMAP +0180 +0300 +0200 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 00C2 +ENCODING 194 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 0 +BITMAP +0180 +03C0 +0660 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 00C3 +ENCODING 195 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 0 +BITMAP +0760 +0FE0 +0DC0 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 00C4 +ENCODING 196 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 19 0 0 +BITMAP +0660 +0660 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 00C5 +ENCODING 197 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 0 +BITMAP +0380 +0440 +0440 +0440 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 00C6 +ENCODING 198 +SWIDTH 990 0 +DWIDTH 22 0 +BBX 21 16 0 0 +BITMAP +00FFF8 +01FFF8 +019800 +031800 +061800 +061800 +0C1800 +0C1FF0 +181FF0 +1FF800 +3FF800 +301800 +601800 +601800 +C01FF8 +C01FF8 +ENDCHAR +STARTCHAR 00C7 +ENCODING 199 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 20 1 -4 +BITMAP +07C0 +1FF0 +3838 +6018 +600C +C000 +C000 +C000 +C000 +C000 +C000 +600C +6018 +3838 +1FF0 +0FC0 +0200 +0300 +0180 +0F00 +ENDCHAR +STARTCHAR 00C8 +ENCODING 200 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +0C00 +0600 +0200 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 00C9 +ENCODING 201 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +0300 +0600 +0400 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 00CA +ENCODING 202 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +0600 +0F00 +1980 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 00CB +ENCODING 203 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 19 2 0 +BITMAP +1980 +1980 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 00CC +ENCODING 204 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 3 20 1 0 +BITMAP +C0 +60 +20 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00CD +ENCODING 205 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 3 20 2 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00CE +ENCODING 206 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 20 0 0 +BITMAP +30 +78 +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00CF +ENCODING 207 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 19 0 0 +BITMAP +CC +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00D0 +ENCODING 208 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 15 16 0 0 +BITMAP +3FE0 +3FF8 +301C +300C +300E +3006 +3006 +FF06 +FF06 +3006 +3006 +300C +300C +303C +3FF8 +3FE0 +ENDCHAR +STARTCHAR 00D1 +ENCODING 209 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0EC0 +1FC0 +1B80 +0000 +C030 +E030 +F030 +F030 +D830 +D830 +CC30 +C630 +C630 +C330 +C1B0 +C1B0 +C0F0 +C0F0 +C070 +C030 +ENDCHAR +STARTCHAR 00D2 +ENCODING 210 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0300 +0180 +0080 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 00D3 +ENCODING 211 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0180 +0300 +0200 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 00D4 +ENCODING 212 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0180 +03C0 +0660 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 00D5 +ENCODING 213 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0760 +0FE0 +0DC0 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 00D6 +ENCODING 214 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 19 1 0 +BITMAP +0660 +0660 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 00D7 +ENCODING 215 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 9 9 2 3 +BITMAP +8100 +E380 +7700 +3E00 +1C00 +3E00 +7700 +E380 +8100 +ENDCHAR +STARTCHAR 00D8 +ENCODING 216 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 16 1 -1 +BITMAP +07C6 +1FFC +383C +701C +603C +C066 +C0C6 +C186 +C306 +C606 +C606 +6C0C +781C +3838 +7FF0 +CFC0 +ENDCHAR +STARTCHAR 00D9 +ENCODING 217 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0C00 +0600 +0200 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DA +ENCODING 218 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0300 +0600 +0400 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DB +ENCODING 219 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0600 +0F00 +1980 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DC +ENCODING 220 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 19 2 0 +BITMAP +1980 +1980 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DD +ENCODING 221 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 14 20 0 0 +BITMAP +0180 +0300 +0200 +0000 +E01C +6018 +3030 +3870 +1860 +0CC0 +0FC0 +0780 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 00DE +ENCODING 222 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 16 2 0 +BITMAP +C000 +C000 +C000 +FF80 +FFE0 +C060 +C030 +C030 +C030 +C030 +C060 +FFE0 +FF80 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00DF +ENCODING 223 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +3E00 +7F00 +E380 +C180 +C180 +C300 +C700 +C600 +C700 +C380 +C0C0 +C060 +C060 +DCE0 +CFC0 +C780 +ENDCHAR +STARTCHAR 00E0 +ENCODING 224 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1800 +0C00 +0400 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 00E1 +ENCODING 225 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +0600 +0C00 +0800 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 00E2 +ENCODING 226 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +0C00 +1E00 +3300 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 00E3 +ENCODING 227 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +3B00 +7F00 +6E00 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 00E4 +ENCODING 228 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3300 +3300 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 00E5 +ENCODING 229 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 18 1 0 +BITMAP +1C00 +2200 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 00E6 +ENCODING 230 +SWIDTH 900 0 +DWIDTH 20 0 +BBX 18 12 1 0 +BITMAP +3F3E00 +7FFF80 +E0E180 +C0C0C0 +03FFC0 +3FFFC0 +7CC000 +C0C000 +C0C0C0 +E1E180 +7F7F80 +3C1E00 +ENDCHAR +STARTCHAR 00E7 +ENCODING 231 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 -4 +BITMAP +1E00 +7F00 +6380 +C180 +C000 +C000 +C000 +C000 +C180 +6380 +7F00 +1E00 +0800 +0C00 +0600 +3C00 +ENDCHAR +STARTCHAR 00E8 +ENCODING 232 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1800 +0C00 +0400 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 00E9 +ENCODING 233 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +0600 +0C00 +0800 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 00EA +ENCODING 234 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +0C00 +1E00 +3300 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 00EB +ENCODING 235 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3300 +3300 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 00EC +ENCODING 236 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 3 16 1 0 +BITMAP +C0 +60 +20 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00ED +ENCODING 237 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 3 16 2 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00EE +ENCODING 238 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 16 0 0 +BITMAP +30 +78 +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00EF +ENCODING 239 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 15 0 0 +BITMAP +CC +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00F0 +ENCODING 240 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +1900 +0F00 +1E00 +3300 +1D00 +7F80 +6180 +E1C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +6180 +7F80 +1E00 +ENDCHAR +STARTCHAR 00F1 +ENCODING 241 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3B00 +7F00 +6E00 +0000 +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 00F2 +ENCODING 242 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +0C00 +0600 +0200 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 00F3 +ENCODING 243 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +0300 +0600 +0400 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 00F4 +ENCODING 244 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +0600 +0F00 +1980 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 00F5 +ENCODING 245 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +1D80 +3F80 +3700 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 00F6 +ENCODING 246 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +1980 +1980 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 00F7 +ENCODING 247 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 8 1 4 +BITMAP +0C00 +0C00 +0000 +FFC0 +FFC0 +0000 +0C00 +0C00 +ENDCHAR +STARTCHAR 00F8 +ENCODING 248 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 11 14 1 -1 +BITMAP +0060 +1F60 +7FC0 +71C0 +E3E0 +C660 +C660 +CC60 +D860 +F8E0 +71C0 +7F80 +DF00 +4000 +ENDCHAR +STARTCHAR 00F9 +ENCODING 249 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3000 +1800 +0800 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 00FA +ENCODING 250 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0600 +0C00 +0800 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 00FB +ENCODING 251 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0C00 +1E00 +3300 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 00FC +ENCODING 252 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +6600 +6600 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 00FD +ENCODING 253 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 11 20 0 -4 +BITMAP +0300 +0600 +0400 +0000 +C060 +C060 +60C0 +60C0 +30C0 +3180 +1980 +1980 +0F00 +0F00 +0700 +0600 +0E00 +0C00 +7C00 +7800 +ENDCHAR +STARTCHAR 00FE +ENCODING 254 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 20 1 -4 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF80 +E180 +C1C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +E180 +FF00 +DE00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00FF +ENCODING 255 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 11 19 0 -4 +BITMAP +1980 +1980 +0000 +C060 +C060 +60C0 +60C0 +30C0 +3180 +1980 +1980 +0F00 +0F00 +0700 +0600 +0E00 +0C00 +7C00 +7800 +ENDCHAR +STARTCHAR 0100 +ENCODING 256 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 19 0 0 +BITMAP +07E0 +07E0 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 0101 +ENCODING 257 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3F00 +3F00 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 0102 +ENCODING 258 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 0 +BITMAP +0820 +0C60 +07C0 +0000 +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +ENDCHAR +STARTCHAR 0103 +ENCODING 259 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +4100 +6300 +3E00 +0000 +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +ENDCHAR +STARTCHAR 0104 +ENCODING 260 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 20 0 -4 +BITMAP +0380 +0380 +06C0 +06C0 +0EE0 +0C60 +0C60 +1830 +1830 +3FF8 +3FF8 +3018 +600C +600C +C006 +C006 +0004 +0008 +0008 +000E +ENDCHAR +STARTCHAR 0105 +ENCODING 261 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +3E00 +7F00 +C180 +C180 +0780 +7F80 +7980 +C180 +C180 +C380 +7F80 +7CC0 +0080 +0100 +0100 +01C0 +ENDCHAR +STARTCHAR 0106 +ENCODING 262 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 20 1 0 +BITMAP +0180 +0300 +0200 +0000 +07C0 +1FF0 +3838 +6018 +600C +C000 +C000 +C000 +C000 +C000 +C000 +600C +6018 +3838 +1FF0 +0FC0 +ENDCHAR +STARTCHAR 0107 +ENCODING 263 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0600 +0C00 +0800 +0000 +1E00 +7F00 +6380 +C180 +C000 +C000 +C000 +C000 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 0108 +ENCODING 264 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 20 1 0 +BITMAP +0300 +0780 +0CC0 +0000 +07C0 +1FF0 +3838 +6018 +600C +C000 +C000 +C000 +C000 +C000 +C000 +600C +6018 +3838 +1FF0 +0FC0 +ENDCHAR +STARTCHAR 0109 +ENCODING 265 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0C00 +1E00 +3300 +0000 +1E00 +7F00 +6380 +C180 +C000 +C000 +C000 +C000 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 010A +ENCODING 266 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 19 1 0 +BITMAP +0180 +0180 +0000 +07C0 +1FF0 +3838 +6018 +600C +C000 +C000 +C000 +C000 +C000 +C000 +600C +6018 +3838 +1FF0 +0FC0 +ENDCHAR +STARTCHAR 010B +ENCODING 267 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +0C00 +0C00 +0000 +1E00 +7F00 +6380 +C180 +C000 +C000 +C000 +C000 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 010C +ENCODING 268 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 20 1 0 +BITMAP +0CC0 +0780 +0300 +0000 +07C0 +1FF0 +3838 +6018 +600C +C000 +C000 +C000 +C000 +C000 +C000 +600C +6018 +3838 +1FF0 +0FC0 +ENDCHAR +STARTCHAR 010D +ENCODING 269 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +1E00 +7F00 +6380 +C180 +C000 +C000 +C000 +C000 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 010E +ENCODING 270 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 13 20 2 0 +BITMAP +3300 +1E00 +0C00 +0000 +FF80 +FFE0 +C070 +C030 +C038 +C018 +C018 +C018 +C018 +C018 +C018 +C030 +C030 +C0E0 +FFE0 +FF80 +ENDCHAR +STARTCHAR 010F +ENCODING 271 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 13 16 1 0 +BITMAP +00D8 +00D8 +00C8 +00C8 +1ED0 +7FC0 +61C0 +C1C0 +C0C0 +C0C0 +C0C0 +C0C0 +E0C0 +61C0 +3FC0 +1EC0 +ENDCHAR +STARTCHAR 0110 +ENCODING 272 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 15 16 0 0 +BITMAP +3FE0 +3FF8 +301C +300C +300E +3006 +3006 +FF06 +FF06 +3006 +3006 +300C +300C +303C +3FF8 +3FE0 +ENDCHAR +STARTCHAR 0111 +ENCODING 273 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +00C0 +0FE0 +0FE0 +00C0 +1EC0 +7FC0 +61C0 +C1C0 +C0C0 +C0C0 +C0C0 +C0C0 +E0C0 +61C0 +3FC0 +1EC0 +ENDCHAR +STARTCHAR 0112 +ENCODING 274 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 19 2 0 +BITMAP +1F80 +1F80 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0113 +ENCODING 275 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +3F00 +3F00 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 0114 +ENCODING 276 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +1040 +18C0 +0F80 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0115 +ENCODING 277 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +2080 +3180 +1F00 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 0116 +ENCODING 278 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 19 2 0 +BITMAP +0600 +0600 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0117 +ENCODING 279 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 15 1 0 +BITMAP +0C00 +0C00 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 0118 +ENCODING 280 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 20 2 -4 +BITMAP +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +0020 +0040 +0040 +0070 +ENDCHAR +STARTCHAR 0119 +ENCODING 281 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +0200 +0400 +0400 +0700 +ENDCHAR +STARTCHAR 011A +ENCODING 282 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +1980 +0F00 +0600 +0000 +FFF0 +FFF0 +C000 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +C000 +C000 +C000 +C000 +C000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 011B +ENCODING 283 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +1E00 +7F80 +6180 +C0C0 +FFC0 +FFC0 +C000 +C000 +E0C0 +7180 +3F80 +1E00 +ENDCHAR +STARTCHAR 011C +ENCODING 284 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0180 +03C0 +0660 +0000 +07E0 +1FF8 +381C +700C +6006 +C000 +C000 +C000 +C0FE +C0FE +C006 +6006 +7006 +381E +1FFC +07E0 +ENDCHAR +STARTCHAR 011D +ENCODING 285 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 20 1 -4 +BITMAP +0C00 +1E00 +3300 +0000 +1EC0 +7FC0 +61C0 +E0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +61C0 +7FC0 +1EC0 +00C0 +C180 +FF80 +3E00 +ENDCHAR +STARTCHAR 011E +ENCODING 286 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0410 +0630 +03E0 +0000 +07E0 +1FF8 +381C +700C +6006 +C000 +C000 +C000 +C0FE +C0FE +C006 +6006 +7006 +381E +1FFC +07E0 +ENDCHAR +STARTCHAR 011F +ENCODING 287 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 20 1 -4 +BITMAP +2080 +3180 +1F00 +0000 +1EC0 +7FC0 +61C0 +E0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +61C0 +7FC0 +1EC0 +00C0 +C180 +FF80 +3E00 +ENDCHAR +STARTCHAR 0120 +ENCODING 288 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 19 1 0 +BITMAP +0180 +0180 +0000 +07E0 +1FF8 +381C +700C +6006 +C000 +C000 +C000 +C0FE +C0FE +C006 +6006 +7006 +381E +1FFC +07E0 +ENDCHAR +STARTCHAR 0121 +ENCODING 289 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 19 1 -4 +BITMAP +0C00 +0C00 +0000 +1EC0 +7FC0 +61C0 +E0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +61C0 +7FC0 +1EC0 +00C0 +C180 +FF80 +3E00 +ENDCHAR +STARTCHAR 0122 +ENCODING 290 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 23 1 -7 +BITMAP +07E0 +1FF8 +381C +700C +6006 +C000 +C000 +C000 +C0FE +C0FE +C006 +6006 +7006 +381E +1FFC +07E0 +0000 +0000 +00C0 +00C0 +0040 +00C0 +0080 +ENDCHAR +STARTCHAR 0123 +ENCODING 291 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 22 1 -4 +BITMAP +0400 +0800 +0800 +0C00 +0C00 +0000 +1EC0 +7FC0 +61C0 +E1C0 +C0C0 +C0C0 +C0C0 +C0C0 +C1C0 +61C0 +7FC0 +1EC0 +00C0 +C180 +FF80 +3E00 +ENDCHAR +STARTCHAR 0124 +ENCODING 292 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0600 +0F00 +1980 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +FFF0 +FFF0 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +ENDCHAR +STARTCHAR 0125 +ENCODING 293 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 20 1 0 +BITMAP +0C00 +1E00 +3300 +0000 +C000 +C000 +C000 +C000 +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 0126 +ENCODING 294 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 14 16 1 0 +BITMAP +6018 +6018 +FFFC +FFFC +6018 +6018 +7FF8 +7FF8 +6018 +6018 +6018 +6018 +6018 +6018 +6018 +6018 +ENDCHAR +STARTCHAR 0127 +ENCODING 295 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +6000 +FE00 +FE00 +6000 +6F00 +7F80 +70C0 +60C0 +60C0 +60C0 +60C0 +60C0 +60C0 +60C0 +60C0 +60C0 +ENDCHAR +STARTCHAR 0128 +ENCODING 296 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 7 20 0 0 +BITMAP +76 +FE +DC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0129 +ENCODING 297 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 7 16 0 0 +BITMAP +76 +FE +DC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012A +ENCODING 298 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 19 0 0 +BITMAP +FC +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012B +ENCODING 299 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 15 0 0 +BITMAP +FC +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012C +ENCODING 300 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 7 20 0 0 +BITMAP +82 +C6 +7C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012D +ENCODING 301 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 7 16 0 0 +BITMAP +82 +C6 +7C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012E +ENCODING 302 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 3 20 1 -4 +BITMAP +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +40 +80 +80 +E0 +ENDCHAR +STARTCHAR 012F +ENCODING 303 +SWIDTH 225 0 +DWIDTH 5 0 +BBX 3 20 0 -4 +BITMAP +60 +60 +00 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +40 +80 +80 +E0 +ENDCHAR +STARTCHAR 0130 +ENCODING 304 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 19 2 0 +BITMAP +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0131 +ENCODING 305 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 2 12 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0132 +ENCODING 306 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 16 2 0 +BITMAP +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +CC30 +CC30 +CE70 +C7E0 +C3C0 +ENDCHAR +STARTCHAR 0133 +ENCODING 307 +SWIDTH 450 0 +DWIDTH 10 0 +BBX 7 20 1 -4 +BITMAP +C6 +C6 +00 +00 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +06 +06 +1E +1C +ENDCHAR +STARTCHAR 0134 +ENCODING 308 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 20 1 0 +BITMAP +0300 +0780 +0CC0 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +C300 +C300 +E700 +7E00 +3C00 +ENDCHAR +STARTCHAR 0135 +ENCODING 309 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 6 20 -1 -4 +BITMAP +30 +78 +CC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0136 +ENCODING 310 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 23 2 -7 +BITMAP +C070 +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +FE00 +E700 +C380 +C1C0 +C0C0 +C0E0 +C070 +C038 +0000 +0000 +0600 +0600 +0200 +0600 +0400 +ENDCHAR +STARTCHAR 0137 +ENCODING 311 +SWIDTH 450 0 +DWIDTH 10 0 +BBX 9 23 1 -7 +BITMAP +C000 +C000 +C000 +C000 +C380 +C700 +CE00 +DC00 +F800 +FC00 +EC00 +CE00 +C600 +C700 +C300 +C380 +0000 +0000 +0C00 +0C00 +0400 +0C00 +0800 +ENDCHAR +STARTCHAR 0138 +ENCODING 312 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +C180 +C300 +C600 +CC00 +D800 +F800 +CC00 +C600 +C600 +C300 +C180 +C180 +ENDCHAR +STARTCHAR 0139 +ENCODING 313 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 20 2 0 +BITMAP +1800 +3000 +2000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 013A +ENCODING 314 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 3 20 1 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013B +ENCODING 315 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 23 2 -7 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +0000 +0000 +0C00 +0C00 +0400 +0C00 +0800 +ENDCHAR +STARTCHAR 013C +ENCODING 316 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 2 23 1 -7 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +C0 +C0 +40 +C0 +80 +ENDCHAR +STARTCHAR 013D +ENCODING 317 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 16 2 0 +BITMAP +C300 +C300 +C100 +C100 +C200 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 013E +ENCODING 318 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 5 16 2 0 +BITMAP +D8 +D8 +C8 +C8 +D0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013F +ENCODING 319 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 9 16 2 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C600 +C600 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0140 +ENCODING 320 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 16 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +CC +CC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0141 +ENCODING 321 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 11 16 0 0 +BITMAP +3000 +3000 +3000 +3100 +3300 +3600 +3C00 +3800 +7000 +F000 +B000 +3000 +3000 +3000 +3FE0 +3FE0 +ENDCHAR +STARTCHAR 0142 +ENCODING 322 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 4 16 0 0 +BITMAP +60 +60 +60 +60 +60 +70 +70 +60 +E0 +E0 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0143 +ENCODING 323 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0300 +0600 +0400 +0000 +C030 +E030 +F030 +F030 +D830 +D830 +CC30 +C630 +C630 +C330 +C1B0 +C1B0 +C0F0 +C0F0 +C070 +C030 +ENDCHAR +STARTCHAR 0144 +ENCODING 324 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0600 +0C00 +0800 +0000 +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 0145 +ENCODING 325 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 23 2 -7 +BITMAP +C030 +E030 +F030 +F030 +D830 +D830 +CC30 +C630 +C630 +C330 +C1B0 +C1B0 +C0F0 +C0F0 +C070 +C030 +0000 +0000 +0600 +0600 +0200 +0600 +0400 +ENDCHAR +STARTCHAR 0146 +ENCODING 326 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 19 1 -7 +BITMAP +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +0000 +0000 +0C00 +0C00 +0400 +0C00 +0800 +ENDCHAR +STARTCHAR 0147 +ENCODING 327 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +1980 +0F00 +0600 +0000 +C030 +E030 +F030 +F030 +D830 +D830 +CC30 +C630 +C630 +C330 +C1B0 +C1B0 +C0F0 +C0F0 +C070 +C030 +ENDCHAR +STARTCHAR 0148 +ENCODING 328 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +DE00 +FF00 +E380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 0149 +ENCODING 329 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 12 16 0 0 +BITMAP +C000 +C000 +4000 +4000 +9BC0 +1FE0 +1C70 +1830 +1830 +1830 +1830 +1830 +1830 +1830 +1830 +1830 +ENDCHAR +STARTCHAR 014A +ENCODING 330 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 13 16 2 0 +BITMAP +CFC0 +DFE0 +F070 +E030 +C038 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C030 +C070 +C7E0 +C3C0 +ENDCHAR +STARTCHAR 014B +ENCODING 331 +SWIDTH 540 0 +DWIDTH 12 0 +BBX 10 16 1 -4 +BITMAP +DF00 +FF80 +E1C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +00C0 +00C0 +03C0 +0380 +ENDCHAR +STARTCHAR 014C +ENCODING 332 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 19 1 0 +BITMAP +07E0 +07E0 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 014D +ENCODING 333 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +3F00 +3F00 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 014E +ENCODING 334 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0820 +0C60 +07C0 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 014F +ENCODING 335 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +2080 +3180 +1F00 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 0150 +ENCODING 336 +SWIDTH 765 0 +DWIDTH 17 0 +BBX 15 20 1 0 +BITMAP +0660 +0CC0 +0CC0 +0000 +07C0 +1FF0 +3838 +701C +600C +C006 +C006 +C006 +C006 +C006 +C006 +600C +701C +3838 +1FF0 +07C0 +ENDCHAR +STARTCHAR 0151 +ENCODING 337 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +1980 +3300 +3300 +0000 +1F00 +3F80 +71C0 +E0E0 +C060 +C060 +C060 +C060 +E0E0 +71C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 0152 +ENCODING 338 +SWIDTH 990 0 +DWIDTH 22 0 +BBX 20 16 1 0 +BITMAP +0F9FF0 +3FDFF0 +787800 +603800 +603800 +C01800 +C01800 +C01FE0 +C01FE0 +C01800 +C01800 +603800 +603800 +707800 +3FDFF0 +0F9FF0 +ENDCHAR +STARTCHAR 0153 +ENCODING 339 +SWIDTH 945 0 +DWIDTH 21 0 +BBX 19 12 1 0 +BITMAP +1F0F00 +3F9F80 +71F0C0 +E0E060 +C06060 +C07FE0 +C07FE0 +C06000 +E0E060 +71F0C0 +3F9FC0 +1F0F80 +ENDCHAR +STARTCHAR 0154 +ENCODING 340 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0600 +0C00 +0800 +0000 +FFC0 +FFE0 +C070 +C030 +C030 +C030 +C070 +FFE0 +FFC0 +C300 +C180 +C1C0 +C0E0 +C060 +C070 +C030 +ENDCHAR +STARTCHAR 0155 +ENCODING 341 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 16 1 0 +BITMAP +0C +18 +10 +00 +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0156 +ENCODING 342 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 23 2 -7 +BITMAP +FFC0 +FFE0 +C070 +C030 +C030 +C030 +C070 +FFE0 +FFC0 +C300 +C180 +C1C0 +C0E0 +C060 +C070 +C030 +0000 +0000 +0600 +0600 +0200 +0600 +0400 +ENDCHAR +STARTCHAR 0157 +ENCODING 343 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 19 1 -7 +BITMAP +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +C0 +C0 +40 +C0 +80 +ENDCHAR +STARTCHAR 0158 +ENCODING 344 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +3300 +1E00 +0C00 +0000 +FFC0 +FFE0 +C070 +C030 +C030 +C030 +C070 +FFE0 +FFC0 +C300 +C180 +C1C0 +C0E0 +C060 +C070 +C030 +ENDCHAR +STARTCHAR 0159 +ENCODING 345 +SWIDTH 315 0 +DWIDTH 7 0 +BBX 6 16 1 0 +BITMAP +CC +78 +30 +00 +DC +FC +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 015A +ENCODING 346 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 20 1 0 +BITMAP +0180 +0300 +0200 +0000 +0FC0 +3FE0 +7070 +6018 +6018 +7000 +3C00 +1FC0 +03F0 +0038 +C018 +C018 +6018 +7070 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 015B +ENCODING 347 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0600 +0C00 +0800 +0000 +3E00 +7F00 +C180 +C000 +F000 +7E00 +1F80 +0380 +0180 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 015C +ENCODING 348 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 20 1 0 +BITMAP +0300 +0780 +0CC0 +0000 +0FC0 +3FE0 +7070 +6018 +6018 +7000 +3C00 +1FC0 +03F0 +0038 +C018 +C018 +6018 +7070 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 015D +ENCODING 349 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +0C00 +1E00 +3300 +0000 +3E00 +7F00 +C180 +C000 +F000 +7E00 +1F80 +0380 +0180 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 015E +ENCODING 350 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 20 1 -4 +BITMAP +0FC0 +3FE0 +7070 +6018 +6018 +7000 +3C00 +1FC0 +03F0 +0038 +C018 +C018 +6018 +7070 +3FF0 +0FC0 +0200 +0300 +0180 +0F00 +ENDCHAR +STARTCHAR 015F +ENCODING 351 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 -4 +BITMAP +3E00 +7F00 +C180 +C000 +F000 +7E00 +1F80 +0380 +0180 +C380 +7F00 +3E00 +0800 +0C00 +0600 +3C00 +ENDCHAR +STARTCHAR 0160 +ENCODING 352 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 13 20 1 0 +BITMAP +0CC0 +0780 +0300 +0000 +0FC0 +3FE0 +7070 +6018 +6018 +7000 +3C00 +1FC0 +03F0 +0038 +C018 +C018 +6018 +7070 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 0161 +ENCODING 353 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +3E00 +7F00 +C180 +C000 +F000 +7E00 +1F80 +0380 +0180 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0162 +ENCODING 354 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 12 20 1 -4 +BITMAP +FFF0 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0200 +0300 +0180 +0F00 +ENDCHAR +STARTCHAR 0163 +ENCODING 355 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 6 20 0 -4 +BITMAP +20 +60 +60 +60 +F8 +F8 +60 +60 +60 +60 +60 +60 +60 +60 +78 +38 +10 +18 +0C +78 +ENDCHAR +STARTCHAR 0164 +ENCODING 356 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 12 20 1 0 +BITMAP +1980 +0F00 +0600 +0000 +FFF0 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0165 +ENCODING 357 +SWIDTH 360 0 +DWIDTH 8 0 +BBX 7 16 1 0 +BITMAP +26 +66 +62 +62 +FC +F8 +60 +60 +60 +60 +60 +60 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0166 +ENCODING 358 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 12 16 1 0 +BITMAP +FFF0 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +3FC0 +3FC0 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0167 +ENCODING 359 +SWIDTH 270 0 +DWIDTH 6 0 +BBX 5 15 0 0 +BITMAP +60 +60 +60 +F8 +F8 +60 +60 +60 +F8 +F8 +60 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0168 +ENCODING 360 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0EC0 +1FC0 +1B80 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0169 +ENCODING 361 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3B00 +7F00 +6E00 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 016A +ENCODING 362 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 19 2 0 +BITMAP +1F80 +1F80 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016B +ENCODING 363 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 15 1 0 +BITMAP +3F00 +3F00 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 016C +ENCODING 364 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +1040 +18C0 +0F80 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016D +ENCODING 365 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +2080 +3180 +1F00 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 016E +ENCODING 366 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0700 +0880 +0880 +0880 +C730 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016F +ENCODING 367 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +1C00 +2200 +2200 +2200 +1C00 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 0170 +ENCODING 368 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 0 +BITMAP +0CC0 +1980 +1980 +0000 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0171 +ENCODING 369 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +3300 +6600 +6600 +0000 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +ENDCHAR +STARTCHAR 0172 +ENCODING 370 +SWIDTH 720 0 +DWIDTH 16 0 +BBX 12 20 2 -4 +BITMAP +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +C030 +E070 +70E0 +3FC0 +1F80 +0100 +0200 +0200 +0380 +ENDCHAR +STARTCHAR 0173 +ENCODING 371 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 9 16 1 -4 +BITMAP +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +E380 +7F80 +3D80 +0100 +0200 +0200 +0380 +ENDCHAR +STARTCHAR 0174 +ENCODING 372 +SWIDTH 945 0 +DWIDTH 21 0 +BBX 21 20 0 0 +BITMAP +003000 +007800 +00CC00 +000000 +C07018 +C07018 +60D830 +60D830 +60D830 +60D830 +318C60 +318C60 +318C60 +318C60 +1B06C0 +1B06C0 +1B06C0 +1B06C0 +0E0380 +0E0380 +ENDCHAR +STARTCHAR 0175 +ENCODING 373 +SWIDTH 675 0 +DWIDTH 15 0 +BBX 15 16 0 0 +BITMAP +0180 +03C0 +0660 +0000 +C106 +C386 +C386 +628C +66CC +26C8 +36D8 +36D8 +1450 +1C70 +1C70 +0C60 +ENDCHAR +STARTCHAR 0176 +ENCODING 374 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 14 20 0 0 +BITMAP +0300 +0780 +0CC0 +0000 +E01C +6018 +3030 +3870 +1860 +0CC0 +0FC0 +0780 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0177 +ENCODING 375 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 11 20 0 -4 +BITMAP +0600 +0F00 +1980 +0000 +C060 +C060 +60C0 +60C0 +30C0 +3180 +1980 +1980 +0F00 +0F00 +0700 +0600 +0E00 +0C00 +7C00 +7800 +ENDCHAR +STARTCHAR 0178 +ENCODING 376 +SWIDTH 630 0 +DWIDTH 14 0 +BBX 14 19 0 0 +BITMAP +0CC0 +0CC0 +0000 +E01C +6018 +3030 +3870 +1860 +0CC0 +0FC0 +0780 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0179 +ENCODING 377 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 12 20 0 0 +BITMAP +0180 +0300 +0200 +0000 +7FF0 +7FF0 +0060 +00C0 +00C0 +0180 +0300 +0600 +0600 +0C00 +1800 +3000 +3000 +6000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 017A +ENCODING 378 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0300 +0600 +0400 +0000 +7FC0 +7FC0 +01C0 +0380 +0700 +0E00 +1C00 +3800 +7000 +E000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 017B +ENCODING 379 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 12 19 0 0 +BITMAP +0300 +0300 +0000 +7FF0 +7FF0 +0060 +00C0 +00C0 +0180 +0300 +0600 +0600 +0C00 +1800 +3000 +3000 +6000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 017C +ENCODING 380 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 15 0 0 +BITMAP +0600 +0600 +0000 +7FC0 +7FC0 +01C0 +0380 +0700 +0E00 +1C00 +3800 +7000 +E000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 017D +ENCODING 381 +SWIDTH 585 0 +DWIDTH 13 0 +BBX 12 20 0 0 +BITMAP +0CC0 +0780 +0300 +0000 +7FF0 +7FF0 +0060 +00C0 +00C0 +0180 +0300 +0600 +0600 +0C00 +1800 +3000 +3000 +6000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 017E +ENCODING 382 +SWIDTH 495 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +1980 +0F00 +0600 +0000 +7FC0 +7FC0 +01C0 +0380 +0700 +0E00 +1C00 +3800 +7000 +E000 +FFC0 +FFC0 +ENDCHAR +ENDFONT diff --git a/examples/fonts/Arial-16.bdf.license b/examples/fonts/Arial-16.bdf.license new file mode 100644 index 0000000..db3e0e3 --- /dev/null +++ b/examples/fonts/Arial-16.bdf.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2017 The Monotype Corporation. All Rights Reserved. Hebrew OpenType Layout logic copyright © 2003 & 2007, Ralph Hancock & John Hudson. + +# SPDX-License-Identifier: MIT From 78a2ea0feb2ea76514f42a6bf9e1b94847475671 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 22 May 2022 00:18:55 -0400 Subject: [PATCH 073/132] Increase min lines similarity Signed-off-by: Alec Delaney --- .pylintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 08e12bf..1f42e5d 100644 --- a/.pylintrc +++ b/.pylintrc @@ -252,7 +252,7 @@ ignore-docstrings=yes ignore-imports=yes # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=12 [BASIC] From 34342d1a14f7433cfc8a5329cb60c96bf12cfa64 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Mon, 30 May 2022 14:25:04 -0400 Subject: [PATCH 074/132] Set language to "en" for documentation Signed-off-by: Alec Delaney --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 6cfd605..b7eeac5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -66,7 +66,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. From 6c9dca1cad065f5d3c23436562aee7d30cdb1e01 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Tue, 7 Jun 2022 15:34:15 -0400 Subject: [PATCH 075/132] Added cp.org link to index.rst --- docs/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index f57da77..9790c2f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -33,7 +33,8 @@ Table of Contents .. toctree:: :caption: Other Links - Download + Download from GitHub + Download Library Bundle CircuitPython Reference Documentation CircuitPython Support Forum Discord Chat From f45f896483b5c6713663f86d12e4be33332bc189 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Tue, 14 Jun 2022 16:46:27 -0400 Subject: [PATCH 076/132] Removed secrets.py --- examples/secrets.py | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 examples/secrets.py diff --git a/examples/secrets.py b/examples/secrets.py deleted file mode 100644 index e05bd25..0000000 --- a/examples/secrets.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: 2022 PaulskPt -# -# SPDX-License-Identifier: MIT -# -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - "ssid": "here your WiFi SSID", - "password": "here your WiFi password", - "aio_username": "here your aio username", - "aio_key": "here your aio key", - "timezone": "Europe/Lisbon", # http://worldtimeapi.org/timezones -} From 8309c62c6a55e1cd26d1c8a812df52225d502714 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Tue, 21 Jun 2022 17:00:37 -0400 Subject: [PATCH 077/132] Removed duplicate-code from library pylint disable Signed-off-by: evaherrada --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a91a11..3343606 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: name: pylint (library code) types: [python] args: - - --disable=consider-using-f-string,duplicate-code + - --disable=consider-using-f-string exclude: "^(docs/|examples/|tests/|setup.py$)" - id: pylint name: pylint (example code) From 59815990be8b6c80fb5e774e8dd5ec5d52ee4082 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Fri, 22 Jul 2022 13:58:40 -0400 Subject: [PATCH 078/132] Changed .env to .venv in README.rst --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index b7564a2..a797fcd 100644 --- a/README.rst +++ b/README.rst @@ -51,8 +51,8 @@ To install in a virtual environment in your current project: .. code-block:: shell mkdir project-name && cd project-name - python3 -m venv .env - source .env/bin/activate + python3 -m venv .venv + source .venv/bin/activate pip3 install adafruit-circuitpython-displayio-layout Usage Example From de0dcfd9c94a1084a7d6f1bde5a1f3cd614fb64e Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Mon, 8 Aug 2022 22:05:54 -0400 Subject: [PATCH 079/132] Switched to pyproject.toml --- .github/workflows/build.yml | 21 ++++++----- .github/workflows/release.yml | 17 +++++---- optional_requirements.txt | 3 ++ pyproject.toml | 49 ++++++++++++++++++++++--- requirements.txt | 13 ++++--- setup.py | 67 ----------------------------------- 6 files changed, 74 insertions(+), 96 deletions(-) create mode 100644 optional_requirements.txt delete mode 100644 setup.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84c964d..22f6582 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,11 +45,10 @@ jobs: - name: Pip install Sphinx, pre-commit run: | pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit - - name: Load graphviz - run: | - sudo apt install graphviz - name: Library version run: git describe --dirty --always --tags + - name: Setup problem matchers + uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 - name: Pre-commit hooks run: | pre-commit run --all-files @@ -63,16 +62,16 @@ jobs: - name: Build docs working-directory: docs run: sphinx-build -E -W -b html . _build/html - - name: Check For setup.py + - name: Check For pyproject.toml id: need-pypi run: | - echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) + echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - name: Build Python package - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') run: | - pip install --upgrade setuptools wheel twine readme_renderer testresources - python setup.py sdist - python setup.py bdist_wheel --universal + pip install --upgrade build twine + for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do + sed -i -e "s/0.0.0-auto.0/1.2.3/" $file; + done; + python -m build twine check dist/* - - name: Setup problem matchers - uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a65e5de..d1b4f8d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,25 +61,28 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Check For setup.py + - name: Check For pyproject.toml id: need-pypi run: | - echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) + echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - name: Set up Python - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install --upgrade build twine - name: Build and publish - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') env: TWINE_USERNAME: ${{ secrets.pypi_username }} TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | - python setup.py sdist + for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do + sed -i -e "s/0.0.0-auto.0/${{github.event.release.tag_name}}/" $file; + done; + python -m build twine upload dist/* diff --git a/optional_requirements.txt b/optional_requirements.txt new file mode 100644 index 0000000..d4e27c4 --- /dev/null +++ b/optional_requirements.txt @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense diff --git a/pyproject.toml b/pyproject.toml index f3c35ae..1c35d1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,47 @@ -# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò +# SPDX-FileCopyrightText: 2022 Alec Delaney for Adafruit Industries # -# SPDX-License-Identifier: Unlicense +# SPDX-License-Identifier: MIT -[tool.black] -target-version = ['py35'] +[build-system] +requires = [ + "setuptools", + "wheel", +] + +[project] +name = "adafruit-circuitpython-displayio-layout" +description = "CircuitPython helper library for displayio layouts and widgets." +version = "0.0.0-auto.0" +readme = "README.rst" +authors = [ + {name = "Adafruit Industries", email = "circuitpython@adafruit.com"} +] +urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout"} +keywords = [ + "adafruit", + "blinka", + "circuitpython", + "micropython", + "displayio_layout", + "displayio", + "gui", + "layout", + "widget", +] +license = {text = "MIT"} +classifiers = [ + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Embedded Systems", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", +] +dynamic = ["dependencies", "optional-dependencies"] + +[tool.setuptools] +packages = ["adafruit_displayio_layout"] + +[tool.setuptools.dynamic] +dependencies = {file = ["requirements.txt"]} +optional-dependencies = {optional = {file = ["optional_requirements.txt"]}} diff --git a/requirements.txt b/requirements.txt index b0b270d..1cfb615 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,10 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# SPDX-FileCopyrightText: Copyright (c) 2021 Tim Cocks for Adafruit Industries +# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries # -# SPDX-License-Identifier: MIT +# SPDX-License-Identifier: Unlicense +Adafruit-Blinka-displayio Adafruit-Blinka -adafruit-blinka-displayio -adafruit-circuitpython-display-shapes -adafruit-circuitpython-imageload -adafruit-circuitpython-display-text adafruit-circuitpython-bitmap-font +adafruit-circuitpython-display-text +adafruit-circuitpython-imageload +adafruit-circuitpython-display-shapes diff --git a/setup.py b/setup.py deleted file mode 100644 index 564522f..0000000 --- a/setup.py +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# SPDX-FileCopyrightText: Copyright (c) 2021 Tim Cocks for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -"""A setuptools based setup module. - -See: -https://packaging.python.org/en/latest/distributing.html -https://github.com/pypa/sampleproject -""" - -from setuptools import setup, find_packages - -# To use a consistent encoding -from codecs import open -from os import path - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, "README.rst"), encoding="utf-8") as f: - long_description = f.read() - -setup( - name="adafruit-circuitpython-displayio-layout", - use_scm_version=True, - setup_requires=["setuptools_scm"], - description="CircuitPython helper library for displayio layouts and widgets.", - long_description=long_description, - long_description_content_type="text/x-rst", - # The project's main homepage. - url="https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout", - # Author details - author="Adafruit Industries", - author_email="circuitpython@adafruit.com", - install_requires=[ - "Adafruit-Blinka", - "adafruit-blinka-displayio", - "adafruit-circuitpython-display-shapes", - "adafruit-circuitpython-imageload", - "adafruit-circuitpython-display-text", - ], - # Choose your license - license="MIT", - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Topic :: Software Development :: Libraries", - "Topic :: System :: Hardware", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - ], - # What does your project relate to? - keywords="adafruit blinka circuitpython micropython displayio_layout displayio gui layout " - "widget", - # You can just specify the packages manually here if your project is - # simple. Or you can use find_packages(). - # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER, - # CHANGE `py_modules=['...']` TO `packages=['...']` - packages=[ - "adafruit_displayio_layout", - "adafruit_displayio_layout.layouts", - "adafruit_displayio_layout.widgets", - ], -) From f60eff012c7026ec681312a912095ff0eb10e6b7 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Mon, 8 Aug 2022 22:51:47 -0400 Subject: [PATCH 080/132] Readd graphviz installation --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22f6582..8f57771 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,9 @@ jobs: - name: Pip install Sphinx, pre-commit run: | pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit + - name: Load graphviz + run: | + apt install graphviz - name: Library version run: git describe --dirty --always --tags - name: Setup problem matchers From 13d8cd1835977a378a5598a2219c92ab6e0bea41 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Mon, 8 Aug 2022 22:55:58 -0400 Subject: [PATCH 081/132] Install graphviz with sudo --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f57771..ae8218a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,7 +47,7 @@ jobs: pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit - name: Load graphviz run: | - apt install graphviz + sudo apt install graphviz - name: Library version run: git describe --dirty --always --tags - name: Setup problem matchers From 6f3c9bab976a371e57aee19412db704baa56e221 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 9 Aug 2022 12:03:54 -0400 Subject: [PATCH 082/132] Add setuptools-scm to build system requirements Signed-off-by: Alec Delaney --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 1c35d1e..39674b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ requires = [ "setuptools", "wheel", + "setuptools-scm", ] [project] From 53e9de1058d9c66ef23838f0427572935b266b61 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 16 Aug 2022 18:09:15 -0400 Subject: [PATCH 083/132] Update version string --- adafruit_displayio_layout/layouts/grid_layout.py | 2 +- adafruit_displayio_layout/layouts/page_layout.py | 2 +- adafruit_displayio_layout/widgets/control.py | 2 +- adafruit_displayio_layout/widgets/switch_round.py | 2 +- adafruit_displayio_layout/widgets/widget.py | 2 +- pyproject.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 34cd086..5d7ebeb 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -31,7 +31,7 @@ import math import displayio -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" diff --git a/adafruit_displayio_layout/layouts/page_layout.py b/adafruit_displayio_layout/layouts/page_layout.py index 1dc1798..040ccbd 100644 --- a/adafruit_displayio_layout/layouts/page_layout.py +++ b/adafruit_displayio_layout/layouts/page_layout.py @@ -32,7 +32,7 @@ import displayio -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" diff --git a/adafruit_displayio_layout/widgets/control.py b/adafruit_displayio_layout/widgets/control.py index 4fbff5a..1aa8a87 100644 --- a/adafruit_displayio_layout/widgets/control.py +++ b/adafruit_displayio_layout/widgets/control.py @@ -21,7 +21,7 @@ """ -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" # pylint: disable=unsubscriptable-object, unnecessary-pass diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index e955224..67b0d51 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -45,7 +45,7 @@ from adafruit_displayio_layout.widgets.easing import back_easeinout as easing -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index 5efbf93..a44603c 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -24,7 +24,7 @@ import displayio -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" # pylint: disable=too-many-arguments diff --git a/pyproject.toml b/pyproject.toml index 39674b0..c036644 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ requires = [ [project] name = "adafruit-circuitpython-displayio-layout" description = "CircuitPython helper library for displayio layouts and widgets." -version = "0.0.0-auto.0" +version = "0.0.0+auto.0" readme = "README.rst" authors = [ {name = "Adafruit Industries", email = "circuitpython@adafruit.com"} From a3d45622a407b98b98c365e95a3f8f4b3d34c044 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 16 Aug 2022 21:09:15 -0400 Subject: [PATCH 084/132] Fix version strings in workflow files --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ae8218a..a60b624 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -74,7 +74,7 @@ jobs: run: | pip install --upgrade build twine for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0-auto.0/1.2.3/" $file; + sed -i -e "s/0.0.0+auto.0/1.2.3/" $file; done; python -m build twine check dist/* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1b4f8d..f3a0325 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,7 +82,7 @@ jobs: TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0-auto.0/${{github.event.release.tag_name}}/" $file; + sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" $file; done; python -m build twine upload dist/* From 206afa4972c9f202c51040228045af7288756f3c Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Mon, 22 Aug 2022 21:36:32 -0400 Subject: [PATCH 085/132] Keep copyright up to date in documentation --- docs/conf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index b7eeac5..e5620a3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,6 +6,7 @@ import os import sys +import datetime sys.path.insert(0, os.path.abspath("..")) @@ -49,7 +50,8 @@ # General information about the project. project = "Adafruit DisplayIO_Layout Library" -copyright = "2021 Tim Cocks" +current_year = str(datetime.datetime.now().year) +copyright = current_year + " Tim Cocks" author = "Tim Cocks" # The version info for the project you're documenting, acts as replacement for From aa66d0fdd6b02e91b8e138dbfc12a7b3d04d3af3 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 23 Aug 2022 17:26:22 -0400 Subject: [PATCH 086/132] Use year duration range for copyright attribution --- docs/conf.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index e5620a3..900705d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,8 +50,14 @@ # General information about the project. project = "Adafruit DisplayIO_Layout Library" +creation_year = "2021" current_year = str(datetime.datetime.now().year) -copyright = current_year + " Tim Cocks" +year_duration = ( + current_year + if current_year == creation_year + else creation_year + " - " + current_year +) +copyright = year_duration + " Tim Cocks" author = "Tim Cocks" # The version info for the project you're documenting, acts as replacement for From 0634dfd015c60fb63180d5e9eb02e24c76ca0c1e Mon Sep 17 00:00:00 2001 From: The-Debarghya Date: Fri, 7 Oct 2022 12:31:33 +0530 Subject: [PATCH 087/132] handle ZeroDivisionError --- adafruit_displayio_layout/widgets/switch_round.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index 67b0d51..fef3547 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -754,6 +754,9 @@ def _animate_switch(self): # Determines the direction of movement, depending upon if the # switch is going from on->off or off->on + if self._animation_time == 0: + self._draw_position(0) + break # constrain the elapsed time elapsed_time = time.monotonic() - start_time if elapsed_time > self._animation_time: From bbae1376e54e658ec7ca33aec92580cc318280dc Mon Sep 17 00:00:00 2001 From: The-Debarghya Date: Sun, 9 Oct 2022 10:35:00 +0530 Subject: [PATCH 088/132] minor change --- .../widgets/switch_round.py | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index fef3547..b27bac1 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -755,23 +755,28 @@ def _animate_switch(self): # switch is going from on->off or off->on if self._animation_time == 0: - self._draw_position(0) - break - # constrain the elapsed time - elapsed_time = time.monotonic() - start_time - if elapsed_time > self._animation_time: - elapsed_time = self._animation_time - - if self._value: - position = ( - 1 - (elapsed_time) / self._animation_time - ) # fraction from 0 to 1 - else: - position = (elapsed_time) / self._animation_time # fraction from 0 to 1 - - # Update the moving elements based on the current position - # apply the "easing" function to the requested position to adjust motion - self._draw_position(easing(position)) # update the switch position + if not self._value: + position = 1 + self._draw_position(1) + else: + position = 0 + self._draw_position(0) + else: #animate over time + # constrain the elapsed time + elapsed_time = time.monotonic() - start_time + if elapsed_time > self._animation_time: + elapsed_time = self._animation_time + + if self._value: + position = ( + 1 - (elapsed_time) / self._animation_time + ) # fraction from 0 to 1 + else: + position = (elapsed_time) / self._animation_time # fraction from 0 to 1 + + # Update the moving elements based on the current position + # apply the "easing" function to the requested position to adjust motion + self._draw_position(easing(position)) # update the switch position # update the switch value once the motion is complete if (position >= 1) and not self._value: From a634e503c1d74e3b914c50b97cadf9f0db6039c9 Mon Sep 17 00:00:00 2001 From: The-Debarghya Date: Sun, 9 Oct 2022 10:40:17 +0530 Subject: [PATCH 089/132] Update switch_round.py --- adafruit_displayio_layout/widgets/switch_round.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index b27bac1..d7310b1 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -772,10 +772,11 @@ def _animate_switch(self): 1 - (elapsed_time) / self._animation_time ) # fraction from 0 to 1 else: - position = (elapsed_time) / self._animation_time # fraction from 0 to 1 + # fraction from 0 to 1 + position = (elapsed_time) / self._animation_time - # Update the moving elements based on the current position - # apply the "easing" function to the requested position to adjust motion + # Update the moving elements based on the current position + # apply the "easing" function to the requested position to adjust motion self._draw_position(easing(position)) # update the switch position # update the switch value once the motion is complete From f2b1656d6d0fd3d0476fc05eb96d6e6564675a74 Mon Sep 17 00:00:00 2001 From: The-Debarghya Date: Sun, 9 Oct 2022 10:50:04 +0530 Subject: [PATCH 090/132] Update switch_round.py --- adafruit_displayio_layout/widgets/switch_round.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index d7310b1..76efe76 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -761,7 +761,7 @@ def _animate_switch(self): else: position = 0 self._draw_position(0) - else: #animate over time + else: # animate over time # constrain the elapsed time elapsed_time = time.monotonic() - start_time if elapsed_time > self._animation_time: @@ -773,10 +773,10 @@ def _animate_switch(self): ) # fraction from 0 to 1 else: # fraction from 0 to 1 - position = (elapsed_time) / self._animation_time + position = (elapsed_time) / self._animation_time - # Update the moving elements based on the current position - # apply the "easing" function to the requested position to adjust motion + # Update the moving elements based on the current position + # apply the "easing" function to the requested position to adjust motion self._draw_position(easing(position)) # update the switch position # update the switch value once the motion is complete From f0e52c1cfb14b67b8b0e796224a47e2d3cb5584f Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 00:02:50 -0400 Subject: [PATCH 091/132] Switching to composite actions --- .github/workflows/build.yml | 70 +----------------------- .github/workflows/release.yml | 88 ------------------------------ .github/workflows/release_gh.yml | 14 +++++ .github/workflows/release_pypi.yml | 14 +++++ 4 files changed, 30 insertions(+), 156 deletions(-) delete mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/release_gh.yml create mode 100644 .github/workflows/release_pypi.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a60b624..041a337 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,71 +10,5 @@ jobs: test: runs-on: ubuntu-latest steps: - - name: Dump GitHub context - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - run: echo "$GITHUB_CONTEXT" - - name: Translate Repo Name For Build Tools filename_prefix - id: repo-name - run: | - echo ::set-output name=repo-name::$( - echo ${{ github.repository }} | - awk -F '\/' '{ print tolower($2) }' | - tr '_' '-' - ) - - name: Set up Python 3.x - uses: actions/setup-python@v2 - with: - python-version: "3.x" - - name: Versions - run: | - python3 --version - - name: Checkout Current Repo - uses: actions/checkout@v1 - with: - submodules: true - - name: Checkout tools repo - uses: actions/checkout@v2 - with: - repository: adafruit/actions-ci-circuitpython-libs - path: actions-ci - - name: Install dependencies - # (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.) - run: | - source actions-ci/install.sh - - name: Pip install Sphinx, pre-commit - run: | - pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit - - name: Load graphviz - run: | - sudo apt install graphviz - - name: Library version - run: git describe --dirty --always --tags - - name: Setup problem matchers - uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 - - name: Pre-commit hooks - run: | - pre-commit run --all-files - - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . - - name: Archive bundles - uses: actions/upload-artifact@v2 - with: - name: bundles - path: ${{ github.workspace }}/bundles/ - - name: Build docs - working-directory: docs - run: sphinx-build -E -W -b html . _build/html - - name: Check For pyproject.toml - id: need-pypi - run: | - echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - - name: Build Python package - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - run: | - pip install --upgrade build twine - for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0+auto.0/1.2.3/" $file; - done; - python -m build - twine check dist/* + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index f3a0325..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -name: Release Actions - -on: - release: - types: [published] - -jobs: - upload-release-assets: - runs-on: ubuntu-latest - steps: - - name: Dump GitHub context - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - run: echo "$GITHUB_CONTEXT" - - name: Translate Repo Name For Build Tools filename_prefix - id: repo-name - run: | - echo ::set-output name=repo-name::$( - echo ${{ github.repository }} | - awk -F '\/' '{ print tolower($2) }' | - tr '_' '-' - ) - - name: Set up Python 3.x - uses: actions/setup-python@v2 - with: - python-version: "3.x" - - name: Versions - run: | - python3 --version - - name: Checkout Current Repo - uses: actions/checkout@v1 - with: - submodules: true - - name: Checkout tools repo - uses: actions/checkout@v2 - with: - repository: adafruit/actions-ci-circuitpython-libs - path: actions-ci - - name: Install deps - run: | - source actions-ci/install.sh - - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . - - name: Upload Release Assets - # the 'official' actions version does not yet support dynamically - # supplying asset names to upload. @csexton's version chosen based on - # discussion in the issue below, as its the simplest to implement and - # allows for selecting files with a pattern. - # https://github.com/actions/upload-release-asset/issues/4 - #uses: actions/upload-release-asset@v1.0.1 - uses: csexton/release-asset-action@master - with: - pattern: "bundles/*" - github-token: ${{ secrets.GITHUB_TOKEN }} - - upload-pypi: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Check For pyproject.toml - id: need-pypi - run: | - echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - - name: Set up Python - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - name: Install dependencies - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - run: | - python -m pip install --upgrade pip - pip install --upgrade build twine - - name: Build and publish - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - env: - TWINE_USERNAME: ${{ secrets.pypi_username }} - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: | - for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" $file; - done; - python -m build - twine upload dist/* diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml new file mode 100644 index 0000000..041a337 --- /dev/null +++ b/.github/workflows/release_gh.yml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Build CI + +on: [pull_request, push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml new file mode 100644 index 0000000..041a337 --- /dev/null +++ b/.github/workflows/release_pypi.yml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Build CI + +on: [pull_request, push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main From b4a89636abb2e9ccedffa0e099dfaefd5e5fc171 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 00:47:00 -0400 Subject: [PATCH 092/132] Updated pylint version to 2.13.0 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3343606..4c43710 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.11.1 + rev: v2.13.0 hooks: - id: pylint name: pylint (library code) From 216291dcc938bd7cff180818fba00fb5064a9257 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 08:15:20 -0400 Subject: [PATCH 093/132] Update pylint to 2.15.5 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c43710..0e5fccc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.13.0 + rev: v2.15.5 hooks: - id: pylint name: pylint (library code) From 9c03435190e66600f2b56e3f6f99319355b6afe9 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 09:12:45 -0400 Subject: [PATCH 094/132] Fix release CI files --- .github/workflows/release_gh.yml | 14 +++++++++----- .github/workflows/release_pypi.yml | 15 ++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml index 041a337..b8aa8d6 100644 --- a/.github/workflows/release_gh.yml +++ b/.github/workflows/release_gh.yml @@ -2,13 +2,17 @@ # # SPDX-License-Identifier: MIT -name: Build CI +name: GitHub Release Actions -on: [pull_request, push] +on: + release: + types: [published] jobs: - test: + upload-release-assets: runs-on: ubuntu-latest steps: - - name: Run Build CI workflow - uses: adafruit/workflows-circuitpython-libs/build@main + - name: Run GitHub Release CI workflow + uses: adafruit/workflows-circuitpython-libs/release-gh@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml index 041a337..65775b7 100644 --- a/.github/workflows/release_pypi.yml +++ b/.github/workflows/release_pypi.yml @@ -2,13 +2,18 @@ # # SPDX-License-Identifier: MIT -name: Build CI +name: PyPI Release Actions -on: [pull_request, push] +on: + release: + types: [published] jobs: - test: + upload-release-assets: runs-on: ubuntu-latest steps: - - name: Run Build CI workflow - uses: adafruit/workflows-circuitpython-libs/build@main + - name: Run PyPI Release CI workflow + uses: adafruit/workflows-circuitpython-libs/release-pypi@main + with: + pypi-username: ${{ secrets.pypi_username }} + pypi-password: ${{ secrets.pypi_password }} From 5bc67d691bb2d35c73db182cab6b18575ea3f778 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 18:34:33 -0400 Subject: [PATCH 095/132] Update .pylintrc for v2.15.5 --- .pylintrc | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/.pylintrc b/.pylintrc index 1f42e5d..40208c3 100644 --- a/.pylintrc +++ b/.pylintrc @@ -26,7 +26,7 @@ jobs=1 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins= +load-plugins=pylint.extensions.no_self_use # Pickle collected data for later comparisons. persistent=yes @@ -54,8 +54,8 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call -disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation,pointless-string-statement,unspecified-encoding +# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call +disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option @@ -225,12 +225,6 @@ max-line-length=100 # Maximum number of lines in a module max-module-lines=1000 -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no @@ -257,38 +251,22 @@ min-similarity-lines=12 [BASIC] -# Naming hint for argument names -argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct argument names argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ -# Naming hint for attribute names -attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct attribute names attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ -# Naming hint for class names -# class-name-hint=[A-Z_][a-zA-Z0-9]+$ -class-name-hint=[A-Z_][a-zA-Z0-9_]+$ - # Regular expression matching correct class names # class-rgx=[A-Z_][a-zA-Z0-9]+$ class-rgx=[A-Z_][a-zA-Z0-9_]+$ -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ @@ -296,9 +274,6 @@ const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # ones are exempt. docstring-min-length=-1 -# Naming hint for function names -function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct function names function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ @@ -309,21 +284,12 @@ good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ # Include a hint for the correct naming format with invalid-name include-naming-hint=no -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -# Naming hint for method names -method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct method names method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ @@ -339,9 +305,6 @@ no-docstring-rgx=^_ # to this list to register other decorators that produce valid properties. property-classes=abc.abstractproperty -# Naming hint for variable names -variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct variable names variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ From 5b0dd7818ac5d3effe049779fe4b993baa07e822 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 20:58:23 -0400 Subject: [PATCH 096/132] Reintroduce graphviz --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 041a337..2470387 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,5 +10,8 @@ jobs: test: runs-on: ubuntu-latest steps: + - name: Load graphviz + run: | + sudo apt install graphviz - name: Run Build CI workflow uses: adafruit/workflows-circuitpython-libs/build@main From 341c6c1c1b4f8087db0b19bbedaa5895cc0aaf1b Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Thu, 1 Sep 2022 20:16:31 -0400 Subject: [PATCH 097/132] Add .venv to .gitignore Signed-off-by: Alec Delaney <89490472+tekktrik@users.noreply.github.com> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 544ec4a..db3d538 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ _build # Virtual environment-specific files .env +.venv # MacOS-specific files *.DS_Store From 5c1e6bfcdaa4f54209bea977d523d90f8d02d6c3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 8 Dec 2022 21:08:39 -0500 Subject: [PATCH 098/132] shorten very long file names --- ...xt_rtc_temp_sensor_test.py => displayio_layout_hotplug_rtc.py} | 0 ..._and_gVars_test.py => displayio_layout_hotplug_temp_sensor.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename examples/hotplug_sensor_examples/{displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py => displayio_layout_hotplug_rtc.py} (100%) rename examples/hotplug_sensor_examples/{displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py => displayio_layout_hotplug_temp_sensor.py} (100%) diff --git a/examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py similarity index 100% rename from examples/hotplug_sensor_examples/displayio_layout_tab_layout_hotplug_ext_rtc_temp_sensor_test.py rename to examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py diff --git a/examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py similarity index 100% rename from examples/hotplug_sensor_examples/displayio_layout_tablayout_hotplug_temp_sensor_datetime_fm_NTP_touch_and_gVars_test.py rename to examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py From bb14a3252329aa873ebdfb91779c6b8991051b62 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:39:55 -0500 Subject: [PATCH 099/132] Add upload url to release action Signed-off-by: Alec Delaney <89490472+tekktrik@users.noreply.github.com> --- .github/workflows/release_gh.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml index b8aa8d6..9acec60 100644 --- a/.github/workflows/release_gh.yml +++ b/.github/workflows/release_gh.yml @@ -16,3 +16,4 @@ jobs: uses: adafruit/workflows-circuitpython-libs/release-gh@main with: github-token: ${{ secrets.GITHUB_TOKEN }} + upload-url: ${{ github.event.release.upload_url }} From a50bd4b07ffad6a8652383b67d83bcc5b2813a39 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Tue, 31 Jan 2023 08:55:54 -0500 Subject: [PATCH 100/132] adding version information to display in files packages --- adafruit_displayio_layout/layouts/tab_layout.py | 3 +++ adafruit_displayio_layout/widgets/cartesian.py | 4 ++++ adafruit_displayio_layout/widgets/easing.py | 5 +++++ adafruit_displayio_layout/widgets/flip_input.py | 5 +++++ adafruit_displayio_layout/widgets/icon_animated.py | 4 ++++ adafruit_displayio_layout/widgets/icon_widget.py | 3 +++ 6 files changed, 24 insertions(+) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index 2d05586..e122c45 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -37,6 +37,9 @@ from adafruit_imageload.tilegrid_inflator import inflate_tilegrid from adafruit_displayio_layout.layouts.page_layout import PageLayout +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + class TabLayout(displayio.Group): """ diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 8a0d147..617f7a3 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -42,6 +42,10 @@ pass +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + + class Cartesian(Widget): """A cartesian widget. The origin is set using ``x`` and ``y``. diff --git a/adafruit_displayio_layout/widgets/easing.py b/adafruit_displayio_layout/widgets/easing.py index 0bfd8ef..56432b8 100644 --- a/adafruit_displayio_layout/widgets/easing.py +++ b/adafruit_displayio_layout/widgets/easing.py @@ -75,6 +75,11 @@ import math + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + + # Modeled after the line y = x def linear_interpolation(pos): """ diff --git a/adafruit_displayio_layout/widgets/flip_input.py b/adafruit_displayio_layout/widgets/flip_input.py index 2e2b8cb..e8a20ee 100644 --- a/adafruit_displayio_layout/widgets/flip_input.py +++ b/adafruit_displayio_layout/widgets/flip_input.py @@ -38,6 +38,11 @@ from adafruit_displayio_layout.widgets.easing import back_easeinout as easein from adafruit_displayio_layout.widgets.easing import back_easeinout as easeout + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + + # pylint: disable=too-many-arguments, too-many-branches, too-many-statements # pylint: disable=too-many-locals, too-many-instance-attributes diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 1d14ebd..0e64cf1 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -32,6 +32,10 @@ from adafruit_displayio_layout.widgets.easing import quadratic_easein as easeout +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + + class IconAnimated(IconWidget): """ diff --git a/adafruit_displayio_layout/widgets/icon_widget.py b/adafruit_displayio_layout/widgets/icon_widget.py index b09ea66..8d559e4 100644 --- a/adafruit_displayio_layout/widgets/icon_widget.py +++ b/adafruit_displayio_layout/widgets/icon_widget.py @@ -30,6 +30,9 @@ from adafruit_displayio_layout.widgets.control import Control from adafruit_displayio_layout.widgets.widget import Widget +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" + class IconWidget(Widget, Control): From fe864353bed58836bb02869fc365035e2bb237f8 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 1 Feb 2023 22:35:36 -0500 Subject: [PATCH 101/132] adding examples to Readthedocs --- docs/examples.rst | 100 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 5 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index 398ee82..34d812a 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -7,6 +7,42 @@ Ensure your device works with this simple test. :caption: examples/displayio_layout_simpletest.py :linenos: +Cartesian plane simple test +--------------------------- + +Create a simple plot plane. + +.. literalinclude:: ../examples/displayio_layout_cartesian_simpletest.py + :caption: examples/displayio_layout_cartesian_simpletest.py + :linenos: + +Cartesian lineplot +--------------------- + +Create a lineplot. + +.. literalinclude:: ../examples/displayio_layout_cartesian_lineplot.py + :caption: examples/displayio_layout_cartesian_lineplot.py + :linenos: + +Cartesian Advanced +--------------------- + +Create three different cartesian planes in the display + +.. literalinclude:: ../examples/displayio_layout_cartesian_advanced_test.py + :caption: examples/displayio_layout_cartesian_advanced_test.py + :linenos: + +GridLayout simple text +------------------------ + +Make green and purple rectangles and a "Hello World" label + +.. literalinclude:: ../examples/displayio_layout_gridlayout_simpletest.py + :caption: examples/displayio_layout_gridlayout_simpletest.py + :linenos: + GridLayout divider lines example -------------------------------- @@ -16,6 +52,15 @@ Create GridLayouts with divider lines. :caption: examples/displayio_layout_gridlayout_dividers.py :linenos: +GridLayout Get Cell +------------------------- + +Make green and purple rectangles and then update the color and text values of the labels using the get_cell() function. + +.. literalinclude:: ../examples/displayio_layout_grid_layout_get_cell_test.py + :caption: examples/displayio_layout_grid_layout_get_cell_test.py + :linenos: + Pygame simple test ------------------ @@ -25,6 +70,42 @@ Display Hello World using Blinka_Displayio_PyGameDisplay. :caption: examples/displayio_layout_gridlayout_pygame_display_simpletest.py :linenos: +Icon Animated simple test +------------------------- + +Creates two animated icons with touch response: zoom and shrink animations. + +.. literalinclude:: ../examples/displayio_layout_icon_animated_simpletest.py + :caption: examples/displayio_layout_icon_animated_simpletest.py + :linenos: + +Page Layout simple test +------------------------- + +Make a PageLayout with two pages and change between them. + +.. literalinclude:: ../examples/displayio_layout_page_layout_simpletest.py + :caption: examples/displayio_layout_page_layout_simpletest.py + :linenos: + +Page Layout advanced test +------------------------- + +Make a PageLayout and illustrate all of it's features + +.. literalinclude:: ../examples/displayio_layout_page_layout_advancedtest.py + :caption: examples/displayio_layout_page_layout_advancedtest.py + :linenos: + +Pygame Switch example +------------------------- + +Make a GridLayout with some Labels in its cells. Displayed with Blinka_Displayio_PyGameDisplay + +.. literalinclude:: ../examples/displayio_layout_page_layout_advancedtest.py + :caption: examples/displayio_layout_page_layout_advancedtest.py + :linenos: + Switch simple test ------------------ @@ -52,11 +133,20 @@ Create three FlipInput selectors. :caption: examples/displayio_layout_flip_input_simpletest.py :linenos: -Cartesian plane simple test ---------------------------- +Tab Layout simple test +----------------------- -Create a simple plot plane. +Make a TabLayout and illustrate the most basic features and usage. -.. literalinclude:: ../examples/displayio_layout_cartesian_simpletest.py - :caption: examples/displayio_layout_cartesian_simpletest.py +.. literalinclude:: ../examples/displayio_layout_tab_layout_simpletest.py + :caption: examples/displayio_layout_tab_layout_simpletest.py + :linenos: + +Tab Layout touch test +--------------------- + +Make a TabLayout change tabs with the touchscreen + +.. literalinclude:: ../examples/displayio_layout_tab_layout_touchtest.py + :caption: examples/ddisplayio_layout_tab_layout_touchtest.py :linenos: From 70fe632fcbaca8c003a4d7bd97dc52bce75f3472 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 5 Feb 2023 18:48:40 -0500 Subject: [PATCH 102/132] Add graphviz as package on RTD --- .readthedocs.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 33c2a61..c8e145a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -12,6 +12,8 @@ build: os: ubuntu-20.04 tools: python: "3" + apt_packages: + - graphviz python: install: From e74a40e60b1ee9194f461d929112b46addcb80b8 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Mon, 6 Feb 2023 16:11:17 -0500 Subject: [PATCH 103/132] Removing Vectorshape Usage --- adafruit_displayio_layout/widgets/__init__.py | 64 ---------------- .../widgets/cartesian.py | 74 +++++++++---------- 2 files changed, 33 insertions(+), 105 deletions(-) diff --git a/adafruit_displayio_layout/widgets/__init__.py b/adafruit_displayio_layout/widgets/__init__.py index cbc4f01..d56d8b0 100644 --- a/adafruit_displayio_layout/widgets/__init__.py +++ b/adafruit_displayio_layout/widgets/__init__.py @@ -1,67 +1,3 @@ # SPDX-FileCopyrightText: 2021 Kevin Matocha, Tim C, Jose David M # # SPDX-License-Identifier: MIT - -""" -`adafruit_displayio_layout.widgets` -======================= -""" - -try: - import vectorio -except ImportError: - pass - -try: - import bitmaptools -except ImportError: - pass - - -# pylint: disable=invalid-name, too-many-arguments -def rectangle_helper( - x0: int, - y0: int, - height: int, - width: int, - bitmap, - color_index: int, - palette, - bitmaptool: bool = True, -) -> None: - """rectangle_helper function - Draws a rectangle to the bitmap given using ``bitmapstools.bitmap`` or - ``vectorio.rectangle`` functions - - :param int x0: rectangle lower corner x position - :param int y0: rectangle lower corner y position - - :param int width: rectangle upper corner x position - :param int height: rectangle upper corner y position - - :param int color_index: palette color index to be used - :param palette: palette object to be used to draw the rectangle - - :param bitmap: bitmap for the rectangle to be drawn - :param bool bitmaptool: uses :py:func:`~bitmaptools.draw_line` to draw the rectanlge. - when `False` uses :py:func:`~vectorio.Rectangle` - - :return: None - :rtype: None - - ┌───────────────────────┐ - │ │ - │ │ - (x0,y0) └───────────────────────┘ - - """ - if bitmaptool: - bitmaptools.fill_region(bitmap, x0, y0, x0 + width, y0 + height, color_index) - else: - rect = vectorio.Rectangle(width, height) - vectorio.VectorShape( - shape=rect, - pixel_shader=palette, - x=x0, - y=y0, - ) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 617f7a3..9c08b1b 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -29,7 +29,8 @@ from adafruit_display_text import bitmap_label import vectorio from adafruit_displayio_layout.widgets.widget import Widget -from adafruit_displayio_layout.widgets import rectangle_helper + +# from adafruit_displayio_layout.widgets import rectangle_helper try: import bitmaptools @@ -138,7 +139,7 @@ class Cartesian(Widget): - **range**: ``xrange`` and ``yrange`` This is the range in absolute units. For example, when using (20-90), the X axis will start at 20 finishing at 90. - However the height of the graph is given by the height parameter. The scale + However, the height of the graph is given by the height parameter. The scale is handled internal to provide a 1:1 experience when you update the graph. @@ -269,14 +270,14 @@ def __init__( self._screen_palette[5] = self._background_color self._corner_bitmap = displayio.Bitmap(10, 10, 5) - rectangle_helper( + + bitmaptools.fill_region( + self._corner_bitmap, 0, 0, self._axes_line_thickness, self._axes_line_thickness, - self._corner_bitmap, 2, - self._screen_palette, ) self._corner_tilegrid = displayio.TileGrid( @@ -336,28 +337,23 @@ def _get_font_height(font, scale: int) -> Tuple[int, int]: return font_width, font_height def _draw_axes(self) -> None: - # Draw x axes line - rectangle_helper( + + bitmaptools.fill_region( + self._axesx_bitmap, 0, 0, - self._axes_line_thickness, self.width, - self._axesx_bitmap, + self._axes_line_thickness, 2, - self._screen_palette, - True, ) - # Draw y axes line - rectangle_helper( + bitmaptools.fill_region( + self._axesy_bitmap, self._axesy_width - self._axes_line_thickness, 0, + self._axesy_width, self.height, - self._axes_line_thickness, - self._axesy_bitmap, 2, - self._screen_palette, - True, ) def _draw_ticks(self) -> None: @@ -382,30 +378,28 @@ def _draw_ticks(self) -> None: + 1, ) self.append(tick_text) - rectangle_helper( + + bitmaptools.fill_region( + self._axesx_bitmap, text_dist, self._axes_line_thickness, - self._tick_line_height, - self._tick_line_thickness, - self._axesx_bitmap, + text_dist + self._tick_line_thickness, + self._axes_line_thickness + self._tick_line_height, 1, - self._screen_palette, - True, ) if self._subticks: if i in subticks: # calc subtick_line_height; force min lineheigt to 1. subtick_line_height = max(1, self._tick_line_height // 2) - rectangle_helper( + + bitmaptools.fill_region( + self._axesx_bitmap, text_dist, self._axes_line_thickness, - subtick_line_height, + text_dist + 1, + self._axes_line_thickness + subtick_line_height, 1, - self._axesx_bitmap, - 1, - self._screen_palette, - True, ) # Y axes ticks @@ -425,34 +419,32 @@ def _draw_ticks(self) -> None: y=0 + self.height - text_dist, ) self.append(tick_text) - rectangle_helper( + + bitmaptools.fill_region( + self._axesy_bitmap, self._axesy_width - self._axes_line_thickness - self._tick_line_height - 1, text_dist, - self._tick_line_thickness, - self._tick_line_height, - self._axesy_bitmap, + self._axesy_width - self._axes_line_thickness - 1, + text_dist + self._tick_line_thickness, 1, - self._screen_palette, - True, ) if self._subticks: if i in subticks: - rectangle_helper( + + bitmaptools.fill_region( + self._axesy_bitmap, self._axesy_width - self._axes_line_thickness - self._tick_line_height // 2 - 1, text_dist, + self._axesy_width - self._axes_line_thickness - 1, + text_dist + 1, 1, - self._tick_line_height // 2, - self._axesy_bitmap, - 1, - self._screen_palette, - True, ) def _draw_pointers(self, x: int, y: int) -> None: From a84c96ceeae8959b0e4a4f66541a3861b0dd4ed5 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Mon, 6 Feb 2023 16:46:25 -0500 Subject: [PATCH 104/132] Removing Vectorshape Usage --- adafruit_displayio_layout/widgets/cartesian.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 9c08b1b..66790a4 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -30,8 +30,6 @@ import vectorio from adafruit_displayio_layout.widgets.widget import Widget -# from adafruit_displayio_layout.widgets import rectangle_helper - try: import bitmaptools except ImportError: From ef459457da6ff12f696a30c639e7892fd804fbad Mon Sep 17 00:00:00 2001 From: Carlos de la Guardia Date: Tue, 2 May 2023 20:42:01 -0600 Subject: [PATCH 105/132] Missing type annotations, refs #50 --- .../layouts/grid_layout.py | 55 ++++--- .../widgets/cartesian.py | 36 +++-- adafruit_displayio_layout/widgets/control.py | 27 +++- adafruit_displayio_layout/widgets/easing.py | 62 ++++---- .../widgets/flip_input.py | 132 ++++++++++------- .../widgets/icon_animated.py | 46 ++++-- .../widgets/icon_widget.py | 31 ++-- .../widgets/switch_round.py | 138 ++++++++++-------- adafruit_displayio_layout/widgets/widget.py | 46 +++--- 9 files changed, 335 insertions(+), 238 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 5d7ebeb..4fec1e1 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -24,7 +24,7 @@ """ try: # Used only for typing - from typing import Tuple + from typing import Any, List, Tuple, Union except ImportError: pass @@ -61,18 +61,18 @@ class GridLayout(displayio.Group): # pylint: disable=too-many-instance-attributes def __init__( self, - x, - y, - width, - height, - grid_size, - cell_padding=0, - divider_lines=False, - h_divider_line_rows=None, - v_divider_line_cols=None, - divider_line_color=0xFFFFFF, - cell_anchor_point=(0.0, 0.0), - ): + x: int, + y: int, + width: int, + height: int, + grid_size: tuple[int, int], + cell_padding: int = 0, + divider_lines: bool = False, + h_divider_line_rows: Union[Tuple[int, ...], List[int], None] = None, + v_divider_line_cols: Union[Tuple[int, ...], List[int], None] = None, + divider_line_color: int = 0xFFFFFF, + cell_anchor_point: Tuple[float, float] = (0.0, 0.0), + ) -> None: super().__init__(x=x, y=y) self.x = x self.y = y @@ -80,13 +80,13 @@ def __init__( self._height = height self.grid_size = grid_size self.cell_padding = cell_padding - self._cell_content_list = [] + self._cell_content_list: List[dict[str, Any]] = [] self._cell_anchor_point = cell_anchor_point - self._divider_lines = [] + self._divider_lines: List[dict[str, Any]] = [] self._divider_color = divider_line_color - self.h_divider_line_rows = h_divider_line_rows - self.v_divider_line_cols = v_divider_line_cols + self.h_divider_line_rows = h_divider_line_rows or tuple() + self.v_divider_line_cols = v_divider_line_cols or tuple() self._divider_lines_enabled = ( (divider_lines is True) @@ -95,19 +95,14 @@ def __init__( ) if divider_lines: - if self.h_divider_line_rows is None: + if h_divider_line_rows is None: self.h_divider_line_rows = [] for _y in range(self.grid_size[1] + 1): self.h_divider_line_rows.append(_y) - if self.v_divider_line_cols is None: + if v_divider_line_cols is None: self.v_divider_line_cols = [] for _x in range(self.grid_size[0] + 1): self.v_divider_line_cols.append(_x) - else: - if not h_divider_line_rows: - self.h_divider_line_rows = tuple() - if not v_divider_line_cols: - self.v_divider_line_cols = tuple() # use at least 1 padding so that content is inside the divider lines if cell_padding == 0 and ( @@ -115,7 +110,7 @@ def __init__( ): self.cell_padding = 1 - def _layout_cells(self): + def _layout_cells(self) -> None: # pylint: disable=too-many-locals, too-many-branches, too-many-statements for cell in self._cell_content_list: if cell["content"] not in self: @@ -382,8 +377,12 @@ def _layout_cells(self): self.append(line_obj["tilegrid"]) def add_content( - self, cell_content, grid_position, cell_size, cell_anchor_point=None - ): + self, + cell_content: displayio.Group, + grid_position: Tuple[int, int], + cell_size: Tuple[int, int], + cell_anchor_point: Union[Tuple[float, ...], None] = None, + ) -> None: """Add a child to the grid. :param cell_content: the content to add to this cell e.g. label, button, etc... @@ -412,7 +411,7 @@ def add_content( self._cell_content_list.append(sub_view_obj) self._layout_cells() - def get_cell(self, cell_coordinates): + def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: """ Return a cells content based on the cell_coordinates. Raises KeyError if coordinates were not found in the GridLayout. diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 66790a4..92f5d0d 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -36,7 +36,7 @@ pass try: - from typing import Tuple + from typing import Any, List, Optional, Tuple except ImportError: pass @@ -178,7 +178,7 @@ def __init__( tick_color: int = 0xFFFFFF, major_tick_stroke: int = 1, major_tick_length: int = 5, - tick_label_font=terminalio.FONT, + tick_label_font: terminalio.FONT = terminalio.FONT, font_color: int = 0xFFFFFF, pointer_radius: int = 1, pointer_color: int = 0xFFFFFF, @@ -186,7 +186,7 @@ def __init__( nudge_x: int = 0, nudge_y: int = 0, verbose: bool = False, - **kwargs, + **kwargs: Any, ) -> None: super().__init__(**kwargs) @@ -319,10 +319,10 @@ def __init__( self._pointer = None self._circle_palette = None - self.plot_line_point = None + self.plot_line_point: Optional[List[Tuple[int, int]]] = None @staticmethod - def _get_font_height(font, scale: int) -> Tuple[int, int]: + def _get_font_height(font: terminalio.FONT, scale: int) -> Tuple[int, int]: if hasattr(font, "get_bounding_box"): font_height = int(scale * font.get_bounding_box()[1]) font_width = int(scale * font.get_bounding_box()[0]) @@ -448,6 +448,10 @@ def _draw_ticks(self) -> None: def _draw_pointers(self, x: int, y: int) -> None: self._circle_palette = displayio.Palette(1) + + # mypy, _circle_palette can't be None at this point + assert self._circle_palette is not None + self._circle_palette[0] = self._pointer_color self._pointer = vectorio.Circle( radius=self._pointer_radius, x=x, y=y, pixel_shader=self._circle_palette @@ -455,7 +459,7 @@ def _draw_pointers(self, x: int, y: int) -> None: self.append(self._pointer) - def _calc_local_xy(self, x: int, y: int) -> (int, int): + def _calc_local_xy(self, x: int, y: int) -> Tuple[int, int]: local_x = ( int((x - self._xrange[0]) * self._factorx * self._valuex) + self._nudge_x ) @@ -469,24 +473,24 @@ def _calc_local_xy(self, x: int, y: int) -> (int, int): ) return (local_x, local_y) - def _check_local_x_in_range(self, local_x): + def _check_local_x_in_range(self, local_x: int) -> bool: return 0 <= local_x < self.width - def _check_local_y_in_range(self, local_y): + def _check_local_y_in_range(self, local_y: int) -> bool: return 0 <= local_y < self.height - def _check_local_xy_in_range(self, local_x, local_y): + def _check_local_xy_in_range(self, local_x: int, local_y: int) -> bool: return self._check_local_x_in_range(local_x) and self._check_local_y_in_range( local_y ) - def _check_x_in_range(self, x): + def _check_x_in_range(self, x: int) -> bool: return self._xrange[0] <= x <= self._xrange[1] - def _check_y_in_range(self, y): + def _check_y_in_range(self, y: int) -> bool: return self._yrange[0] <= y <= self._yrange[1] - def _check_xy_in_range(self, x, y): + def _check_xy_in_range(self, x: int, y: int) -> bool: return self._check_x_in_range(x) and self._check_y_in_range(y) def _add_point(self, x: int, y: int) -> None: @@ -587,6 +591,9 @@ def update_pointer(self, x: int, y: int) -> None: :return: None rtype: None """ + # mypy, plot_line_point can't be None at this point + assert self.plot_line_point is not None + self._add_point(x, y) if not self._pointer: self._draw_pointers( @@ -609,6 +616,9 @@ def add_plot_line(self, x: int, y: int) -> None: rtype: None """ + # mypy, plot_line_point can't be None at this point + assert self.plot_line_point is not None + self._add_point(x, y) if len(self.plot_line_point) > 1: bitmaptools.draw_line( @@ -620,7 +630,7 @@ def add_plot_line(self, x: int, y: int) -> None: 1, ) - def clear_plot_lines(self, palette_index=5): + def clear_plot_lines(self, palette_index: int = 5) -> None: """clear_plot_lines function. clear all added lines diff --git a/adafruit_displayio_layout/widgets/control.py b/adafruit_displayio_layout/widgets/control.py index 1aa8a87..f9e5a2b 100644 --- a/adafruit_displayio_layout/widgets/control.py +++ b/adafruit_displayio_layout/widgets/control.py @@ -21,6 +21,12 @@ """ +try: + from typing import Optional, Tuple +except ImportError: + pass + + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -46,20 +52,24 @@ class Control: def __init__( self, - ): + ) -> None: self.touch_boundary = ( - None # `self.touch_boundary` should be updated by the subclass + 0, + 0, + 0, + 0, # `self.touch_boundary` should be updated by the subclass ) # Tuple of [x, y, width, height]: [int, int, int, int] all in pixel units # where x,y define the upper left corner # and width and height define the size of the `touch_boundary` - def contains(self, touch_point): + def contains(self, touch_point: Tuple[int, int, Optional[int]]) -> bool: """Checks if the Control was touched. Returns True if the touch_point is within the Control's touch_boundary. - :param touch_point: x,y location of the screen, converted to local coordinates. - :type touch_point: Tuple[x,y] + :param touch_point: x, y, p location of the screen, converted to local coordinates, plus + an optional pressure value for screens that support it. + :type touch_point: Tuple[int, int, Optional[int]] :return: Boolean """ @@ -82,11 +92,12 @@ def contains(self, touch_point): return False # place holder touch_handler response functions - def selected(self, touch_point): + def selected(self, touch_point: Tuple[int, int, Optional[int]]) -> None: """Response function when Control is selected. Should be overridden by subclass. - :param touch_point: x,y location of the screen, converted to local coordinates. - :type touch_point: Tuple[x,y] + :param touch_point: x, y, p location of the screen, converted to local coordinates, plus + an optional pressure value for screens that support it. + :type touch_point: Tuple[int, int, Optional[int]] :return: None """ diff --git a/adafruit_displayio_layout/widgets/easing.py b/adafruit_displayio_layout/widgets/easing.py index 56432b8..9a1e9a9 100644 --- a/adafruit_displayio_layout/widgets/easing.py +++ b/adafruit_displayio_layout/widgets/easing.py @@ -81,7 +81,7 @@ # Modeled after the line y = x -def linear_interpolation(pos): +def linear_interpolation(pos: float) -> float: """ Easing function for animations: Linear Interpolation. """ @@ -89,7 +89,7 @@ def linear_interpolation(pos): # Modeled after the parabola y = x^2 -def quadratic_easein(pos): +def quadratic_easein(pos: float) -> float: """ Easing function for animations: Quadratic Ease In """ @@ -97,7 +97,7 @@ def quadratic_easein(pos): # Modeled after the parabola y = -x^2 + 2x -def quadratic_easeout(pos): +def quadratic_easeout(pos: float) -> float: """ Easing function for animations: Quadratic Ease Out. """ @@ -107,7 +107,7 @@ def quadratic_easeout(pos): # Modeled after the piecewise quadratic # y = (1/2)((2x)^2) ; [0, 0.5) # y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] -def quadratic_easeinout(pos): +def quadratic_easeinout(pos: float) -> float: """ Easing function for animations: Quadratic Ease In & Out """ @@ -117,7 +117,7 @@ def quadratic_easeinout(pos): # Modeled after the cubic y = x^3 -def cubic_easein(pos): +def cubic_easein(pos: float) -> float: """ Easing function for animations: Cubic Ease In """ @@ -125,7 +125,7 @@ def cubic_easein(pos): # Modeled after the cubic y = (x - 1)^3 + 1 -def cubic_easeout(pos): +def cubic_easeout(pos: float) -> float: """ Easing function for animations: Cubic Ease Out """ @@ -136,7 +136,7 @@ def cubic_easeout(pos): # Modeled after the piecewise cubic # y = (1/2)((2x)^3) ; [0, 0.5) # y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] -def cubic_easeinout(pos): +def cubic_easeinout(pos: float) -> float: """ Easing function for animations: Cubic Ease In & Out """ @@ -147,7 +147,7 @@ def cubic_easeinout(pos): # Modeled after the quartic x^4 -def quartic_easein(pos): +def quartic_easein(pos: float) -> float: """ Easing function for animations: Quartic Ease In """ @@ -155,7 +155,7 @@ def quartic_easein(pos): # Modeled after the quartic y = 1 - (x - 1)^4 -def quartic_easeout(pos): +def quartic_easeout(pos: float) -> float: """ Easing function for animations: Quartic Ease Out """ @@ -166,7 +166,7 @@ def quartic_easeout(pos): # Modeled after the piecewise quartic # y = (1/2)((2x)^4) ; [0, 0.5) # y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] -def quartic_easeinout(pos): +def quartic_easeinout(pos: float) -> float: """ Easing function for animations: Quartic Ease In & Out """ @@ -177,7 +177,7 @@ def quartic_easeinout(pos): # Modeled after the quintic y = x^5 -def quintic_easein(pos): +def quintic_easein(pos: float) -> float: """ Easing function for animations: Quintic Ease In """ @@ -185,7 +185,7 @@ def quintic_easein(pos): # Modeled after the quintic y = (x - 1)^5 + 1 -def quintic_easeout(pos): +def quintic_easeout(pos: float) -> float: """ Easing function for animations: Quintic Ease Out """ @@ -196,7 +196,7 @@ def quintic_easeout(pos): # Modeled after the piecewise quintic # y = (1/2)((2x)^5) ; [0, 0.5) # y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] -def quintic_easeinout(pos): +def quintic_easeinout(pos: float) -> float: """ Easing function for animations: Quintic Ease In & Out """ @@ -207,7 +207,7 @@ def quintic_easeinout(pos): # Modeled after quarter-cycle of sine wave -def sine_easein(pos): +def sine_easein(pos: float) -> float: """ Easing function for animations: Sine Ease In """ @@ -215,7 +215,7 @@ def sine_easein(pos): # Modeled after quarter-cycle of sine wave (different phase) -def sine_easeout(pos): +def sine_easeout(pos: float) -> float: """ Easing function for animations: Sine Ease Out """ @@ -223,7 +223,7 @@ def sine_easeout(pos): # Modeled after half sine wave -def sine_easeinout(pos): +def sine_easeinout(pos: float) -> float: """ Easing function for animations: Sine Ease In & Out """ @@ -231,7 +231,7 @@ def sine_easeinout(pos): # Modeled after shifted quadrant IV of unit circle -def circular_easein(pos): +def circular_easein(pos: float) -> float: """ Easing function for animations: Circular Ease In """ @@ -239,7 +239,7 @@ def circular_easein(pos): # Modeled after shifted quadrant II of unit circle -def circular_easeout(pos): +def circular_easeout(pos: float) -> float: """ Easing function for animations: Circular Ease Out """ @@ -249,7 +249,7 @@ def circular_easeout(pos): # Modeled after the piecewise circular function # y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) # y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] -def circular_easeinout(pos): +def circular_easeinout(pos: float) -> float: """ Easing function for animations: Circular Ease In & Out """ @@ -259,7 +259,7 @@ def circular_easeinout(pos): # Modeled after the exponential function y = 2^(10(x - 1)) -def exponential_easein(pos): +def exponential_easein(pos: float) -> float: """ Easing function for animations: Exponential Ease In """ @@ -269,7 +269,7 @@ def exponential_easein(pos): # Modeled after the exponential function y = -2^(-10x) + 1 -def exponential_easeout(pos): +def exponential_easeout(pos: float) -> float: """ Easing function for animations: Exponential Ease Out """ @@ -281,7 +281,7 @@ def exponential_easeout(pos): # Modeled after the piecewise exponential # y = (1/2)2^(10(2x - 1)) ; [0,0.5) # y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] -def exponential_easeinout(pos): +def exponential_easeinout(pos: float) -> float: """ Easing function for animations: Exponential Ease In & Out """ @@ -293,7 +293,7 @@ def exponential_easeinout(pos): # Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) -def elastic_easein(pos): +def elastic_easein(pos: float) -> float: """ Easing function for animations: Elastic Ease In """ @@ -301,7 +301,7 @@ def elastic_easein(pos): # Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 -def elastic_easeout(pos): +def elastic_easeout(pos: float) -> float: """ Easing function for animations: Elastic Ease Out """ @@ -311,7 +311,7 @@ def elastic_easeout(pos): # Modeled after the piecewise exponentially-damped sine wave: # y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) # y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] -def elastic_easeinout(pos): +def elastic_easeinout(pos: float) -> float: """ Easing function for animations: Elastic Ease In & Out """ @@ -324,7 +324,7 @@ def elastic_easeinout(pos): # Modeled after the overshooting cubic y = x^3-x*sin(x*pi) -def back_easein(pos): +def back_easein(pos: float) -> float: """ Easing function for animations: Back Ease In """ @@ -332,7 +332,7 @@ def back_easein(pos): # Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) -def back_easeout(pos): +def back_easeout(pos: float) -> float: """ Easing function for animations: Back Ease Out """ @@ -343,7 +343,7 @@ def back_easeout(pos): # Modeled after the piecewise overshooting cubic function: # y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) # y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] -def back_easeinout(pos): +def back_easeinout(pos: float) -> float: """ Easing function for animations: Back Ease In & Out """ @@ -354,14 +354,14 @@ def back_easeinout(pos): return 0.5 * (1 - (fos * fos * fos - fos * math.sin(fos * math.pi))) + 0.5 -def bounce_easein(pos): +def bounce_easein(pos: float) -> float: """ Easing function for animations: Bounce Ease In """ return 1 - bounce_easeout(1 - pos) -def bounce_easeout(pos): +def bounce_easeout(pos: float) -> float: """ Easing function for animations: Bounce Ease Out """ @@ -374,7 +374,7 @@ def bounce_easeout(pos): return (54 / 5.0 * pos * pos) - (513 / 25.0 * pos) + 268 / 25.0 -def bounce_easeinout(pos): +def bounce_easeinout(pos: float) -> float: """ Easing function for animations: Bounce Ease In & Out """ diff --git a/adafruit_displayio_layout/widgets/flip_input.py b/adafruit_displayio_layout/widgets/flip_input.py index e8a20ee..2245069 100644 --- a/adafruit_displayio_layout/widgets/flip_input.py +++ b/adafruit_displayio_layout/widgets/flip_input.py @@ -38,6 +38,11 @@ from adafruit_displayio_layout.widgets.easing import back_easeinout as easein from adafruit_displayio_layout.widgets.easing import back_easeinout as easeout +try: + from typing import Any, List, Optional, Tuple +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -88,25 +93,25 @@ class FlipInput(Widget, Control): def __init__( self, - display, + display: displayio.Display, *, - value_list=None, - font=FONT, - font_scale=1, - color=0xFFFFFF, - value=0, # initial value, index into the value_list - arrow_touch_padding=0, # additional touch padding on the arrow sides of the Widget - arrow_color=0x333333, - arrow_outline=0x555555, - arrow_height=30, - arrow_width=30, - arrow_gap=5, - alt_touch_padding=0, # touch padding on the non-arrow sides of the Widget - horizontal=True, - animation_time=None, - cool_down=0.0, - **kwargs, - ): + value_list: List[str], + font: FONT = FONT, + font_scale: int = 1, + color: int = 0xFFFFFF, + value: int = 0, # initial value, index into the value_list + arrow_touch_padding: int = 0, # additional touch padding on the arrow sides of the Widget + arrow_color: int = 0x333333, + arrow_outline: int = 0x555555, + arrow_height: int = 30, + arrow_width: int = 30, + arrow_gap: int = 5, + alt_touch_padding: int = 0, # touch padding on the non-arrow sides of the Widget + horizontal: bool = True, + animation_time: Optional[float] = None, + cool_down: float = 0.0, + **kwargs: Any, + ) -> None: super().__init__(**kwargs) # Group elements for the FlipInput. # 0. The text @@ -183,6 +188,14 @@ def __init__( xposition = xposition + glyph.shift_x + # Something is wrong if left, right, top, or bottom are still None here + assert ( + right is not None + and left is not None + and top is not None + and bottom is not None + ) + self._bounding_box = [ 0, 0, @@ -212,7 +225,7 @@ def __init__( if horizontal: # horizontal orientation, add arrow padding to x-dimension and # alt_padding to y-dimension - self.touch_boundary = [ + self.touch_boundary = ( self._bounding_box[0] - self._arrow_gap - arrow_height @@ -221,10 +234,10 @@ def __init__( self._bounding_box[2] + 2 * (self._arrow_gap + arrow_height + self._arrow_touch_padding), self._bounding_box[3] + 2 * self._alt_touch_padding, - ] + ) else: # vertical orientation, add arrow padding to y-dimension and # alt_padding to x-dimension - self.touch_boundary = [ + self.touch_boundary = ( self._bounding_box[0] - self._alt_touch_padding, self._bounding_box[1] - self._arrow_gap @@ -233,7 +246,7 @@ def __init__( self._bounding_box[2] + 2 * self._alt_touch_padding, self._bounding_box[3] + 2 * (self._arrow_gap + arrow_height + self._arrow_touch_padding), - ] + ) # create the Up/Down arrows self._update_position() # call Widget superclass function to reposition @@ -331,7 +344,7 @@ def __init__( ) # Draw function to update the current value - def _update_value(self, new_value, animate=True): + def _update_value(self, new_value: int, animate: bool = True) -> None: if ( (self._animation_time is not None) @@ -376,20 +389,20 @@ def _update_value(self, new_value, animate=True): start_bitmap.blit(0, 0, self._label.bitmap) # get the bitmap1 position offsets - bitmap1_offset = [ + bitmap1_offset = ( -1 * self._left + self._label.tilegrid.x, -1 * self._top + self._label.tilegrid.y, - ] + ) # hide the label group self.pop(0) # update the value label and get the bitmap offsets self._label.text = str(self.value_list[new_value]) - bitmap2_offset = [ + bitmap2_offset = ( -1 * self._left + self._label.tilegrid.x, -1 * self._top + self._label.tilegrid.y, - ] + ) # animate between old and new bitmaps _animate_bitmap( @@ -424,7 +437,7 @@ def _update_value(self, new_value, animate=True): self._display.auto_refresh = True self._update_position() # call Widget superclass function to reposition - def _ok_to_change(self): # checks state variable and timers to determine + def _ok_to_change(self) -> bool: # checks state variable and timers to determine # if an update is allowed if self._cool_down < 0: # if cool_down is negative, require ``released`` # to be called before next change @@ -433,7 +446,9 @@ def _ok_to_change(self): # checks state variable and timers to determine return False # cool_down time has not transpired return True - def contains(self, touch_point): # overrides, then calls Control.contains(x,y) + def contains( + self, touch_point: Tuple[int, int, Optional[int]] + ) -> bool: # overrides, then calls Control.contains(x,y) """Returns True if the touch_point is within the widget's touch_boundary.""" ###### @@ -449,7 +464,7 @@ def contains(self, touch_point): # overrides, then calls Control.contains(x,y) return super().contains((touch_x, touch_y, 0)) - def selected(self, touch_point): + def selected(self, touch_point: Tuple[int, int, Optional[int]]) -> None: """Response function when the Control is selected. Increases value when upper half is pressed and decreases value when lower half is pressed.""" @@ -489,14 +504,14 @@ def selected(self, touch_point): time.monotonic() ) # value changed, so update cool_down timer - def released(self): + def released(self) -> None: """Response function when the Control is released. Resets the state variables for handling situation when ``cool_down`` is < 0 that requires `released()` before reacting another another `selected()`.""" self._pressed = False @property - def value(self): + def value(self) -> int: """The value index displayed on the widget. For the setter, the input can either be an `int` index into the ``value_list`` or can be a `str` that matches one of the items in the ``value_list``. If `int`, @@ -508,7 +523,9 @@ def value(self): return self._value @value.setter - def value(self, new_value): # Set the value based on the index or on the string. + def value( + self, new_value: int | str + ) -> int | None: # Set the value based on the index or on the string. if isinstance(new_value, str): # for an input string, search the value_list try: new_value = self.value_list.index(new_value) @@ -528,14 +545,14 @@ def value(self, new_value): # Set the value based on the index or on the string # draw_position - Draws two bitmaps into the target bitmap with offsets. # Allows values < 0.0 and > 1.0 for "springy" easing functions def _draw_position( - target_bitmap, - bitmap1, - bitmap1_offset, - bitmap2, - bitmap2_offset, - position=0.0, - horizontal=True, -): + target_bitmap: displayio.Bitmap, + bitmap1: displayio.Bitmap, + bitmap1_offset: Tuple[int, int], + bitmap2: displayio.Bitmap, + bitmap2_offset: Tuple[int, int], + position: float = 0.0, + horizontal: bool = True, +) -> None: x_offset1 = bitmap1_offset[0] y_offset1 = bitmap1_offset[1] @@ -582,7 +599,16 @@ def _draw_position( # pylint: disable=invalid-name # _blit_constrained: Copies bitmaps with constraints to the dimensions -def _blit_constrained(target, x, y, source, x1=None, y1=None, x2=None, y2=None): +def _blit_constrained( + target: displayio.Bitmap, + x: int, + y: int, + source: displayio.Bitmap, + x1: Optional[int] = None, + y1: Optional[int] = None, + x2: Optional[int] = None, + y2: Optional[int] = None, +) -> None: if x1 is None: x1 = 0 if y1 is None: @@ -625,17 +651,17 @@ def _blit_constrained(target, x, y, source, x1=None, y1=None, x2=None, y2=None): # _animate_bitmap - performs animation of scrolling between two bitmaps def _animate_bitmap( - display, - target_bitmap, - bitmap1, - bitmap1_offset, - bitmap2, - bitmap2_offset, - start_position, - end_position, - animation_time, - horizontal, -): + display: displayio.Display, + target_bitmap: displayio.Bitmap, + bitmap1: displayio.Bitmap, + bitmap1_offset: Tuple[int, int], + bitmap2: displayio.Bitmap, + bitmap2_offset: Tuple[int, int], + start_position: float, + end_position: float, + animation_time: float, + horizontal: bool, +) -> None: start_time = time.monotonic() diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 0e64cf1..c39dde8 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -25,12 +25,17 @@ import time from math import pi import bitmaptools -from displayio import TileGrid, Bitmap, Palette +from displayio import TileGrid, Bitmap, Display, Palette import adafruit_imageload from adafruit_displayio_layout.widgets.icon_widget import IconWidget from adafruit_displayio_layout.widgets.easing import quadratic_easeout as easein from adafruit_displayio_layout.widgets.easing import quadratic_easein as easeout +try: + from typing import Any, Optional, Tuple +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -79,8 +84,12 @@ class IconAnimated(IconWidget): @classmethod def init_class( - cls, display=None, max_scale=1.5, max_icon_size=(80, 80), max_color_depth=256 - ): + cls, + display: Optional[Display], + max_scale: float = 1.5, + max_icon_size: Tuple[int, int] = (80, 80), + max_color_depth: int = 256, + ) -> None: """ Initializes the IconAnimated Class variables, including preallocating memory buffers for the icon zoom bitmap and icon zoom palette. @@ -134,14 +143,14 @@ def init_class( def __init__( self, - label_text, - icon, - on_disk=False, - scale=None, - angle=4, - animation_time=0.15, - **kwargs, - ): + label_text: str, + icon: str, + on_disk: bool = False, + scale: Optional[float] = None, + angle: float = 4, + animation_time: float = 0.15, + **kwargs: Any, + ) -> None: if self.__class__.display is None: raise ValueError( @@ -169,11 +178,11 @@ def __init__( self._angle = (angle / 360) * 2 * pi # in degrees, convert to radians self._zoomed = False # state variable for zoom status - def zoom_animation(self, touch_point): + def zoom_animation(self, touch_point: Tuple[int, int, Optional[int]]) -> None: """Performs zoom animation when icon is pressed. :param touch_point: x,y location of the screen. - :type touch_point: Tuple[x,y] + :type touch_point: Tuple[int, int, Optional[int]] :return: None """ @@ -200,6 +209,9 @@ def zoom_animation(self, touch_point): animation_bitmap = self.__class__.bitmap_buffer animation_palette = self.__class__.palette_buffer + # For mypy, if class is configured correctly this must be true + assert isinstance(self.__class__.display, Display) + # store the current display refresh setting refresh_status = self.__class__.display.auto_refresh @@ -264,11 +276,11 @@ def zoom_animation(self, touch_point): self._zoomed = True - def zoom_out_animation(self, touch_point): + def zoom_out_animation(self, touch_point: Tuple[int, int, Optional[int]]) -> None: """Performs un-zoom animation when icon is released. :param touch_point: x,y location of the screen. - :type touch_point: Tuple[x,y] + :type touch_point: Tuple[int, int, Optional[int]] :return: None """ @@ -277,6 +289,9 @@ def zoom_out_animation(self, touch_point): animation_bitmap = self.__class__.bitmap_buffer animation_palette = self.__class__.palette_buffer + # For mypy, if class is configured correctly this must be true + assert isinstance(self.__class__.display, Display) + # store the current display refresh setting refresh_status = self.__class__.display.auto_refresh @@ -284,6 +299,7 @@ def zoom_out_animation(self, touch_point): # Animation: shrink down to the original size start_time = time.monotonic() + while True: elapsed_time = time.monotonic() - start_time position = max(0.0, easeout(1 - (elapsed_time / self._animation_time))) diff --git a/adafruit_displayio_layout/widgets/icon_widget.py b/adafruit_displayio_layout/widgets/icon_widget.py index 8d559e4..fd993e3 100644 --- a/adafruit_displayio_layout/widgets/icon_widget.py +++ b/adafruit_displayio_layout/widgets/icon_widget.py @@ -30,6 +30,12 @@ from adafruit_displayio_layout.widgets.control import Control from adafruit_displayio_layout.widgets.widget import Widget +try: + from typing import Any, Optional, Tuple +except ImportError: + pass + + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -61,13 +67,13 @@ class IconWidget(Widget, Control): def __init__( self, - label_text, - icon, - on_disk=False, - transparent_index=None, - label_background=None, - **kwargs - ): + label_text: str, + icon: str, + on_disk: bool = False, + transparent_index: Optional[int] = None, + label_background: Optional[int] = None, + **kwargs: Any + ) -> None: super().__init__(**kwargs) self._icon = icon @@ -95,20 +101,23 @@ def __init__( _label.background_color = label_background self.append(_label) - self.touch_boundary = ( + self.touch_boundary: Tuple[int, int, int, int] = ( 0, 0, image.width, image.height + _label.bounding_box[3], ) - def contains(self, touch_point): # overrides, then calls Control.contains(x,y) + def contains( + self, touch_point: Tuple[int, int, Optional[int]] + ) -> bool: # overrides, then calls Control.contains(x,y) """Checks if the IconWidget was touched. Returns True if the touch_point is within the IconWidget's touch_boundary. - :param touch_point: x,y location of the screen, converted to local coordinates. - :type touch_point: Tuple[x,y] + :param touch_point: x, y, p location of the screen, converted to local coordinates, plus + an optional pressure value for screens that support it. + :type touch_point: Tuple[int, int, Optional[int]] :return: Boolean """ diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index 76efe76..0ada0ca 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -44,6 +44,11 @@ # modify the "easing" function that is imported to change the switch animation behaviour from adafruit_displayio_layout.widgets.easing import back_easeinout as easing +try: + from typing import Any, Optional, Tuple, Union +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -419,32 +424,43 @@ class functions. The `Widget` class handles the overall sizing and positioning def __init__( self, - x=0, - y=0, - width=None, # recommend to default to - height=40, - touch_padding=0, - horizontal=True, # horizontal orientation - flip=False, # flip the direction of the switch movement - anchor_point=None, - anchored_position=None, - fill_color_off=(66, 44, 66), - fill_color_on=(0, 100, 0), - outline_color_off=(30, 30, 30), - outline_color_on=(0, 60, 0), - background_color_off=(255, 255, 255), - background_color_on=(0, 60, 0), - background_outline_color_off=None, # default to background_color_off - background_outline_color_on=None, # default to background_color_on - switch_stroke=2, - text_stroke=None, # default to switch_stroke - display_button_text=True, - animation_time=0.2, # animation duration (in seconds) - value=False, # initial value - **kwargs, - ): + x: int = 0, + y: int = 0, + width: Optional[int] = None, # recommend to default to + height: int = 40, + touch_padding: int = 0, + horizontal: bool = True, # horizontal orientation + flip: bool = False, # flip the direction of the switch movement + anchor_point: Optional[Tuple[float, float]] = None, + anchored_position: Optional[Tuple[int, int]] = None, + fill_color_off: Union[Tuple[int, int, int], int] = (66, 44, 66), + fill_color_on: Union[Tuple[int, int, int], int] = (0, 100, 0), + outline_color_off: Union[Tuple[int, int, int], int] = (30, 30, 30), + outline_color_on: Union[Tuple[int, int, int], int] = (0, 60, 0), + background_color_off: Union[Tuple[int, int, int], int] = (255, 255, 255), + background_color_on: Union[Tuple[int, int, int], int] = (0, 60, 0), + background_outline_color_off: Union[ + Tuple[int, int, int], int, None + ] = None, # default to background_color_off + background_outline_color_on: Union[ + Tuple[int, int, int], int, None + ] = None, # default to background_color_on + switch_stroke: int = 2, + text_stroke: Optional[int] = None, # default to switch_stroke + display_button_text: bool = True, + animation_time: float = 0.2, # animation duration (in seconds) + value: bool = False, # initial value + **kwargs: Any, + ) -> None: + + self._radius = height // 2 + + # If width is not provided, then use the preferred aspect ratio + if width is None: + width = 4 * self._radius # initialize the Widget superclass (x, y, scale) + # self._height and self._width are set in the super call super().__init__(x=x, y=y, height=height, width=width, **kwargs) # Group elements for SwitchRound: # 0. switch_roundrect: The switch background @@ -460,17 +476,6 @@ def __init__( self._horizontal = horizontal self._flip = flip - # height and width internal variables are treated before considering rotation - self._height = self.height - self._radius = self.height // 2 - - # If width is not provided, then use the preferred aspect ratio - if self._width is None: - self._width = 4 * self._radius - else: - self._width = self.width - print("width set!") - if background_outline_color_off is None: background_outline_color_off = background_color_off if background_outline_color_on is None: @@ -505,12 +510,15 @@ def __init__( self._create_switch() - def _create_switch(self): + def _create_switch(self) -> None: # The main function that creates the switch display elements switch_x = self._radius switch_y = self._radius + # These are Optional[int] values, let mypy know they should never be None here + assert self._height is not None and self._width is not None + # Define the motion "keyframes" that define the switch movement if self._horizontal: # horizontal switch orientation self._x_motion = self._width - 2 * self._radius - 1 @@ -614,12 +622,12 @@ def _create_switch(self): self._width, ] - self.touch_boundary = [ + self.touch_boundary = ( self._bounding_box[0] - self._touch_padding, self._bounding_box[1] - self._touch_padding, self._bounding_box[2] + 2 * self._touch_padding, self._bounding_box[3] + 2 * self._touch_padding, - ] + ) # Store initial positions of moving elements to be used in _draw_function self._switch_initial_x = self._switch_circle.x @@ -661,7 +669,7 @@ def _create_switch(self): # due to any changes that might have occurred in the bounding_box self._update_position() - def _get_offset_position(self, position): + def _get_offset_position(self, position: float) -> Tuple[int, int, float]: # Function to calculate the offset position (x, y, angle) of the moving # elements of an animated widget. Designed to be flexible depending upon # the widget's desired response. @@ -683,7 +691,7 @@ def _get_offset_position(self, position): return x_offset, y_offset, angle_offset - def _draw_position(self, position): + def _draw_position(self, position: float) -> None: # Draw the position of the slider. # The position parameter is a float between 0 and 1 (0= off, 1= on). @@ -733,7 +741,7 @@ def _draw_position(self, position): self._text_0.hidden = False self._text_1.hidden = True - def _animate_switch(self): + def _animate_switch(self) -> None: # The animation function for the switch. # 1. Move the switch # 2. Update the self._value to the opposite of its current value. @@ -756,10 +764,10 @@ def _animate_switch(self): if self._animation_time == 0: if not self._value: - position = 1 + position = 1.0 self._draw_position(1) else: - position = 0 + position = 0.0 self._draw_position(0) else: # animate over time # constrain the elapsed time @@ -789,11 +797,12 @@ def _animate_switch(self): self._value = False break - def selected(self, touch_point): + def selected(self, touch_point: Tuple[int, int, Optional[int]]) -> None: """Response function when Switch is selected. When selected, the switch position and value is changed with an animation. - :param touch_point: x,y location of the screen, in absolute display coordinates. + :param touch_point: x, y, p location of the screen, converted to local coordinates, plus + an optional pressure value for screens that support it. :return: None """ @@ -809,11 +818,14 @@ def selected(self, touch_point): # touch_point is adjusted for group's x,y position before sending to super() super().selected((touch_x, touch_y, 0)) - def contains(self, touch_point): # overrides, then calls Control.contains(x,y) + def contains( + self, touch_point: Tuple[int, int, Optional[int]] + ) -> bool: # overrides, then calls Control.contains(x,y) """Checks if the Widget was touched. Returns True if the touch_point is within the Control's touch_boundary. - :param touch_point: x,y location of the screen, in absolute display coordinates. + :param touch_point: x, y, p location of the screen, converted to local coordinates, plus + an optional pressure value for screens that support it. :return: Boolean """ @@ -825,7 +837,7 @@ def contains(self, touch_point): # overrides, then calls Control.contains(x,y) return super().contains((touch_x, touch_y, 0)) @property - def value(self): + def value(self) -> bool: """The current switch value (Boolean). :return: Boolean @@ -833,17 +845,19 @@ def value(self): return self._value @value.setter - def value(self, new_value): + def value(self, new_value: bool) -> None: if new_value != self._value: - fake_touch_point = [0, 0, 0] # send an arbitrary touch_point + fake_touch_point = (0, 0, 0) # send an arbitrary touch_point self.selected(fake_touch_point) @property - def width(self): + def width(self) -> int: + # Type is Optional[int], let mypy know that it can't be None here + assert self._width is not None return self._width @width.setter - def width(self, new_width): + def width(self, new_width: int) -> None: if self._width is None: self._width = 4 * self._radius else: @@ -851,16 +865,18 @@ def width(self, new_width): self._create_switch() @property - def height(self): + def height(self) -> int: + # Type is Optional[int], let mypy know that it can't be None here + assert self._height is not None return self._height @height.setter - def height(self, new_height): + def height(self, new_height: int) -> None: self._height = new_height self._radius = new_height // 2 self._create_switch() - def resize(self, new_width, new_height): + def resize(self, new_width: int, new_height: int) -> None: """Resize the switch to a new requested width and height. :param int new_width: requested maximum width @@ -893,7 +909,7 @@ def resize(self, new_width, new_height): ###### color support functions ###### -def _color_to_tuple(value): +def _color_to_tuple(value: Union[Tuple[int, int, int], int]) -> Tuple[int, int, int]: """Converts a color from a 24-bit integer to a tuple. :param value: RGB LED desired value - can be a RGB tuple or a 24-bit integer. """ @@ -905,12 +921,16 @@ def _color_to_tuple(value): r = value >> 16 g = (value >> 8) & 0xFF b = value & 0xFF - return [r, g, b] + return (r, g, b) raise ValueError("Color must be a tuple or 24-bit integer value.") -def _color_fade(start_color, end_color, fraction): +def _color_fade( + start_color: Union[Tuple[int, int, int], int], + end_color: Union[Tuple[int, int, int], int], + fraction: float, +) -> Tuple[int, ...]: """Linear extrapolation of a color between two RGB colors (tuple or 24-bit integer). :param start_color: starting color :param end_color: ending color @@ -930,4 +950,4 @@ def _color_fade(start_color, end_color, fraction): faded_color[i] = start_color[i] - int( (start_color[i] - end_color[i]) * fraction ) - return faded_color + return tuple(faded_color) diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index a44603c..8764ddd 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -24,6 +24,12 @@ import displayio +try: + from typing import Optional, Tuple +except ImportError: + pass + + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -166,14 +172,14 @@ class Widget(displayio.Group): def __init__( self, - x=0, - y=0, - scale=1, - width=None, - height=None, - anchor_point=None, - anchored_position=None, - ): + x: int = 0, + y: int = 0, + scale: float = 1, + width: Optional[int] = None, + height: Optional[int] = None, + anchor_point: Optional[Tuple[float, float]] = None, + anchored_position: Optional[Tuple[int, int]] = None, + ) -> None: super().__init__(x=x, y=y, scale=scale) # send x,y and scale to Group @@ -195,7 +201,7 @@ def __init__( self._update_position() - def resize(self, new_width, new_height): + def resize(self, new_width: int, new_height: int) -> None: """Resizes the widget dimensions (for use with automated layout functions). **IMPORTANT:** The `resize` function should be overridden by the subclass definition. @@ -218,7 +224,7 @@ def resize(self, new_width, new_height): self._bounding_box[2] = new_width self._bounding_box[3] = new_height - def _update_position(self): + def _update_position(self) -> None: """ Widget class function for updating the widget's *x* and *y* position based upon the `anchor_point` and `anchored_position` values. The subclass should @@ -240,31 +246,31 @@ def _update_position(self): ) @property - def width(self): + def width(self) -> int: """The widget width, in pixels. (getter only) :return: int """ - return self._width + return self._width or 0 @property - def height(self): + def height(self) -> int: """The widget height, in pixels. (getter only) :return: int """ - return self._height + return self._height or 0 @property - def bounding_box(self): + def bounding_box(self) -> Tuple[int, ...]: """The boundary of the widget. [x, y, width, height] in Widget's local coordinates (in pixels). (getter only) :return: Tuple[int, int, int, int]""" - return self._bounding_box + return tuple(self._bounding_box) @property - def anchor_point(self): + def anchor_point(self) -> Optional[Tuple[float, float]]: """The anchor point for positioning the widget, works in concert with `anchored_position` The relative (X,Y) position of the widget where the anchored_position is placed. For example (0.0, 0.0) is the Widget's upper left corner, @@ -275,12 +281,12 @@ def anchor_point(self): return self._anchor_point @anchor_point.setter - def anchor_point(self, new_anchor_point): + def anchor_point(self, new_anchor_point: Tuple[float, float]) -> None: self._anchor_point = new_anchor_point self._update_position() @property - def anchored_position(self): + def anchored_position(self) -> Optional[Tuple[int, int]]: """The anchored position (in pixels) for positioning the widget, works in concert with `anchor_point`. The `anchored_position` is the x,y pixel position for the placement of the Widget's `anchor_point`. @@ -292,6 +298,6 @@ def anchored_position(self): return self._anchored_position @anchored_position.setter - def anchored_position(self, new_anchored_position): + def anchored_position(self, new_anchored_position: Tuple[int, int]) -> None: self._anchored_position = new_anchored_position self._update_position() From a96f864dbed5f1b4fe85444eb7e6a092e22044aa Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 8 May 2023 16:59:10 -0500 Subject: [PATCH 106/132] set initial value to list. annotate palette and circle --- adafruit_displayio_layout/widgets/cartesian.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 92f5d0d..be45ac7 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -317,9 +317,9 @@ def __init__( self.append(self._screen_tilegrid) self.append(self._corner_tilegrid) - self._pointer = None - self._circle_palette = None - self.plot_line_point: Optional[List[Tuple[int, int]]] = None + self._pointer: Optional[vectorio.Circle] = None + self._circle_palette: Optional[displayio.Palette] = None + self.plot_line_point: List[Tuple[int, int]] = [] @staticmethod def _get_font_height(font: terminalio.FONT, scale: int) -> Tuple[int, int]: @@ -449,9 +449,6 @@ def _draw_pointers(self, x: int, y: int) -> None: self._circle_palette = displayio.Palette(1) - # mypy, _circle_palette can't be None at this point - assert self._circle_palette is not None - self._circle_palette[0] = self._pointer_color self._pointer = vectorio.Circle( radius=self._pointer_radius, x=x, y=y, pixel_shader=self._circle_palette @@ -591,8 +588,6 @@ def update_pointer(self, x: int, y: int) -> None: :return: None rtype: None """ - # mypy, plot_line_point can't be None at this point - assert self.plot_line_point is not None self._add_point(x, y) if not self._pointer: @@ -616,8 +611,6 @@ def add_plot_line(self, x: int, y: int) -> None: rtype: None """ - # mypy, plot_line_point can't be None at this point - assert self.plot_line_point is not None self._add_point(x, y) if len(self.plot_line_point) > 1: @@ -641,5 +634,5 @@ def clear_plot_lines(self, palette_index: int = 5) -> None: rtype: None """ - self.plot_line_point = None + self.plot_line_point = [] self._plot_bitmap.fill(palette_index) From 5386e82138239b103c2c56816d65061c3da80f36 Mon Sep 17 00:00:00 2001 From: Carlos de la Guardia Date: Mon, 8 May 2023 18:09:18 -0600 Subject: [PATCH 107/132] address review comments --- adafruit_displayio_layout/layouts/grid_layout.py | 4 ++-- adafruit_displayio_layout/widgets/icon_animated.py | 3 ++- adafruit_displayio_layout/widgets/widget.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 4fec1e1..a882f23 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -24,7 +24,7 @@ """ try: # Used only for typing - from typing import Any, List, Tuple, Union + from typing import Any, List, Optional, Tuple, Union except ImportError: pass @@ -381,7 +381,7 @@ def add_content( cell_content: displayio.Group, grid_position: Tuple[int, int], cell_size: Tuple[int, int], - cell_anchor_point: Union[Tuple[float, ...], None] = None, + cell_anchor_point: Optional[Tuple[float, ...]] = None, ) -> None: """Add a child to the grid. diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index c39dde8..74ebd20 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -25,7 +25,7 @@ import time from math import pi import bitmaptools -from displayio import TileGrid, Bitmap, Display, Palette +from displayio import TileGrid, Bitmap, Palette import adafruit_imageload from adafruit_displayio_layout.widgets.icon_widget import IconWidget from adafruit_displayio_layout.widgets.easing import quadratic_easeout as easein @@ -33,6 +33,7 @@ try: from typing import Any, Optional, Tuple + from displayio import Display # pylint: disable=ungrouped-imports except ImportError: pass diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index 8764ddd..af84194 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -174,7 +174,7 @@ def __init__( self, x: int = 0, y: int = 0, - scale: float = 1, + scale: int = 1, width: Optional[int] = None, height: Optional[int] = None, anchor_point: Optional[Tuple[float, float]] = None, From 5f23ebd24f8bfefa71a4b58ff2b4078c098a3359 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 9 May 2023 18:25:21 -0500 Subject: [PATCH 108/132] assert not None instead of Display --- adafruit_displayio_layout/widgets/icon_animated.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 74ebd20..943c436 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -211,7 +211,7 @@ def zoom_animation(self, touch_point: Tuple[int, int, Optional[int]]) -> None: animation_palette = self.__class__.palette_buffer # For mypy, if class is configured correctly this must be true - assert isinstance(self.__class__.display, Display) + assert self.__class__.display is not None # store the current display refresh setting refresh_status = self.__class__.display.auto_refresh @@ -291,7 +291,7 @@ def zoom_out_animation(self, touch_point: Tuple[int, int, Optional[int]]) -> Non animation_palette = self.__class__.palette_buffer # For mypy, if class is configured correctly this must be true - assert isinstance(self.__class__.display, Display) + assert self.__class__.display is not None # store the current display refresh setting refresh_status = self.__class__.display.auto_refresh From 7b6352b6e2e2c6c67e80afa31aa2ca582820e92c Mon Sep 17 00:00:00 2001 From: Tekktrik Date: Tue, 9 May 2023 20:26:25 -0400 Subject: [PATCH 109/132] Update pre-commit hooks Signed-off-by: Tekktrik --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e5fccc..70ade69 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,21 +4,21 @@ repos: - repo: https://github.com/python/black - rev: 22.3.0 + rev: 23.3.0 hooks: - id: black - repo: https://github.com/fsfe/reuse-tool - rev: v0.14.0 + rev: v1.1.2 hooks: - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.4.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.15.5 + rev: v2.17.4 hooks: - id: pylint name: pylint (library code) From 2b57d319bf6b7820236e536a45ec5becc36d74aa Mon Sep 17 00:00:00 2001 From: Tekktrik Date: Wed, 10 May 2023 22:30:33 -0400 Subject: [PATCH 110/132] Run pre-commit --- adafruit_displayio_layout/layouts/grid_layout.py | 1 - adafruit_displayio_layout/layouts/tab_layout.py | 2 -- adafruit_displayio_layout/widgets/cartesian.py | 4 ---- adafruit_displayio_layout/widgets/flip_input.py | 10 +--------- adafruit_displayio_layout/widgets/icon_animated.py | 2 -- adafruit_displayio_layout/widgets/icon_widget.py | 1 - adafruit_displayio_layout/widgets/switch_round.py | 2 -- adafruit_displayio_layout/widgets/widget.py | 1 - examples/displayio_layout_flip_input_simpletest.py | 1 - examples/displayio_layout_page_layout_simpletest.py | 1 - .../displayio_layout_pygame_display_switch_round.py | 1 - examples/displayio_layout_switch_multiple.py | 1 - examples/displayio_layout_switch_simpletest.py | 1 - .../displayio_layout_hotplug_rtc.py | 3 --- .../displayio_layout_hotplug_temp_sensor.py | 2 +- 15 files changed, 2 insertions(+), 31 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index a882f23..5274054 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -153,7 +153,6 @@ def _layout_cells(self) -> None: pass if not hasattr(cell["content"], "anchor_point"): - cell["content"].x = ( int(grid_position_x * self._width / grid_size_x) + self.cell_padding diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index e122c45..e63f021 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -85,7 +85,6 @@ def __init__( showing_tab_transparent_indexes: Optional[Union[int, Tuple[int, int]]] = None, tab_count: int = None, ): - if display is None: # pylint: disable=import-outside-toplevel import board @@ -283,7 +282,6 @@ def handle_touch_events(self, touch_event): if touch_event: if 0 <= touch_event[1] <= self.tab_height: - touched_tab_index = touch_event[0] // ( self.display.width // self.tab_count ) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index be45ac7..d47722e 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -188,7 +188,6 @@ def __init__( verbose: bool = False, **kwargs: Any, ) -> None: - super().__init__(**kwargs) self._verbose = verbose @@ -335,7 +334,6 @@ def _get_font_height(font: terminalio.FONT, scale: int) -> Tuple[int, int]: return font_width, font_height def _draw_axes(self) -> None: - bitmaptools.fill_region( self._axesx_bitmap, 0, @@ -432,7 +430,6 @@ def _draw_ticks(self) -> None: if self._subticks: if i in subticks: - bitmaptools.fill_region( self._axesy_bitmap, self._axesy_width @@ -446,7 +443,6 @@ def _draw_ticks(self) -> None: ) def _draw_pointers(self, x: int, y: int) -> None: - self._circle_palette = displayio.Palette(1) self._circle_palette[0] = self._pointer_color diff --git a/adafruit_displayio_layout/widgets/flip_input.py b/adafruit_displayio_layout/widgets/flip_input.py index 2245069..1474225 100644 --- a/adafruit_displayio_layout/widgets/flip_input.py +++ b/adafruit_displayio_layout/widgets/flip_input.py @@ -262,9 +262,7 @@ def __init__( # Add the two arrow triangles, if required if (arrow_color is not None) or (arrow_outline is not None): - if horizontal: # horizontal orientation, add left and right arrows - if ( (arrow_width is not None) and (arrow_height is not None) @@ -304,7 +302,6 @@ def __init__( ) ) else: # vertical orientation, add upper and lower arrows - if ( (arrow_height is not None) and (arrow_width is not None) @@ -345,13 +342,11 @@ def __init__( # Draw function to update the current value def _update_value(self, new_value: int, animate: bool = True) -> None: - if ( (self._animation_time is not None) and (self._animation_time > 0) # If animation is required and (animate) ): - if ((new_value - self.value) == 1) or ( (self.value == (len(self.value_list) - 1)) and (new_value == 0) ): # wrap around @@ -553,7 +548,6 @@ def _draw_position( position: float = 0.0, horizontal: bool = True, ) -> None: - x_offset1 = bitmap1_offset[0] y_offset1 = bitmap1_offset[1] x_offset2 = bitmap2_offset[0] @@ -598,6 +592,7 @@ def _draw_position( # pylint: disable=invalid-name + # _blit_constrained: Copies bitmaps with constraints to the dimensions def _blit_constrained( target: displayio.Bitmap, @@ -662,7 +657,6 @@ def _animate_bitmap( animation_time: float, horizontal: bool, ) -> None: - start_time = time.monotonic() if start_position > end_position: # direction is decreasing: "out" @@ -686,7 +680,6 @@ def _animate_bitmap( display.auto_refresh = True while True: - this_time = time.monotonic() target_position = ( start_position @@ -709,7 +702,6 @@ def _animate_bitmap( ) display.auto_refresh = True else: - _draw_position( target_bitmap, bitmap1, diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 943c436..2e5db2f 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -152,7 +152,6 @@ def __init__( animation_time: float = 0.15, **kwargs: Any, ) -> None: - if self.__class__.display is None: raise ValueError( "Must initialize class using\n" @@ -206,7 +205,6 @@ def zoom_animation(self, touch_point: Tuple[int, int, Optional[int]]) -> None: ) if self._animation_time > 0: - animation_bitmap = self.__class__.bitmap_buffer animation_palette = self.__class__.palette_buffer diff --git a/adafruit_displayio_layout/widgets/icon_widget.py b/adafruit_displayio_layout/widgets/icon_widget.py index fd993e3..318d1c6 100644 --- a/adafruit_displayio_layout/widgets/icon_widget.py +++ b/adafruit_displayio_layout/widgets/icon_widget.py @@ -111,7 +111,6 @@ def __init__( def contains( self, touch_point: Tuple[int, int, Optional[int]] ) -> bool: # overrides, then calls Control.contains(x,y) - """Checks if the IconWidget was touched. Returns True if the touch_point is within the IconWidget's touch_boundary. diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index 0ada0ca..78a4cd7 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -452,7 +452,6 @@ def __init__( value: bool = False, # initial value **kwargs: Any, ) -> None: - self._radius = height // 2 # If width is not provided, then use the preferred aspect ratio @@ -758,7 +757,6 @@ def _animate_switch(self) -> None: start_time = time.monotonic() # set the starting time for animation while True: - # Determines the direction of movement, depending upon if the # switch is going from on->off or off->on diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index af84194..6bf6dc6 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -180,7 +180,6 @@ def __init__( anchor_point: Optional[Tuple[float, float]] = None, anchored_position: Optional[Tuple[int, int]] = None, ) -> None: - super().__init__(x=x, y=y, scale=scale) # send x,y and scale to Group # diff --git a/examples/displayio_layout_flip_input_simpletest.py b/examples/displayio_layout_flip_input_simpletest.py index 2a64645..ed46952 100755 --- a/examples/displayio_layout_flip_input_simpletest.py +++ b/examples/displayio_layout_flip_input_simpletest.py @@ -101,7 +101,6 @@ display.auto_refresh = True while True: - p = ts.touch_point # print("touch_point p: {}".format(p)) # print the touch point diff --git a/examples/displayio_layout_page_layout_simpletest.py b/examples/displayio_layout_page_layout_simpletest.py index 28dd2b5..15fcf97 100644 --- a/examples/displayio_layout_page_layout_simpletest.py +++ b/examples/displayio_layout_page_layout_simpletest.py @@ -55,6 +55,5 @@ main_group.append(test_page_layout) while True: - time.sleep(1) test_page_layout.next_page() diff --git a/examples/displayio_layout_pygame_display_switch_round.py b/examples/displayio_layout_pygame_display_switch_round.py index 63eb69c..addf09b 100644 --- a/examples/displayio_layout_pygame_display_switch_round.py +++ b/examples/displayio_layout_pygame_display_switch_round.py @@ -72,7 +72,6 @@ main_group.append(my_switch) while display.running: - # get mouse up events ev = pygame.event.get(eventtype=pygame.MOUSEBUTTONUP) # proceed events diff --git a/examples/displayio_layout_switch_multiple.py b/examples/displayio_layout_switch_multiple.py index 95faff8..5e09289 100755 --- a/examples/displayio_layout_switch_multiple.py +++ b/examples/displayio_layout_switch_multiple.py @@ -107,7 +107,6 @@ # Start the main loop while True: - p = ts.touch_point # get any touches on the screen if p: # Check each switch if the touch point is within the switch touch area diff --git a/examples/displayio_layout_switch_simpletest.py b/examples/displayio_layout_switch_simpletest.py index b890d84..46ae7e2 100644 --- a/examples/displayio_layout_switch_simpletest.py +++ b/examples/displayio_layout_switch_simpletest.py @@ -34,7 +34,6 @@ # Start the main loop while True: - p = ts.touch_point # get any touches on the screen if p: # Check each switch if the touch point is within the switch touch area diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py index f56413f..757d105 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py @@ -27,7 +27,6 @@ class gVars: def __init__(self): - self.gVarsDict = { 0: "my_debug", 1: "rtc", @@ -524,7 +523,6 @@ def get_temp(): def handle_dt(dt): - RetVal = False s = "Date/time: " sYY = str(dt[yy]) @@ -652,5 +650,4 @@ def main(): if __name__ == "__main__": - main() diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py index a4a3301..e420995 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py @@ -39,7 +39,6 @@ class gVars: def __init__(self): - self.gVarsDict = { 0: "my_debug", 1: "rtc", @@ -487,6 +486,7 @@ def refresh_from_NTP(): From: https://learn.adafruit.com/making-a-pyportal-user-interface-displayio/the-full-code """ + # This will handle switching Images and Icons def set_image(group, filename): """Set the image file for a given goup for display. From 4b786ccc94bc5e2869b19d71e6571ef60a0fb1c9 Mon Sep 17 00:00:00 2001 From: Tekktrik Date: Sun, 14 May 2023 13:00:32 -0400 Subject: [PATCH 111/132] Update .pylintrc, fix jQuery for docs Signed-off-by: Tekktrik --- .pylintrc | 2 +- docs/conf.py | 1 + docs/requirements.txt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 40208c3..f945e92 100644 --- a/.pylintrc +++ b/.pylintrc @@ -396,4 +396,4 @@ min-public-methods=1 # Exceptions that will emit a warning when being caught. Defaults to # "Exception" -overgeneral-exceptions=Exception +overgeneral-exceptions=builtins.Exception diff --git a/docs/conf.py b/docs/conf.py index 900705d..72546d5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,7 @@ # ones. extensions = [ "sphinx.ext.autodoc", + "sphinxcontrib.jquery", "sphinx.ext.intersphinx", "sphinx.ext.napoleon", "sphinx.ext.todo", diff --git a/docs/requirements.txt b/docs/requirements.txt index 88e6733..797aa04 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,3 +3,4 @@ # SPDX-License-Identifier: Unlicense sphinx>=4.0.0 +sphinxcontrib-jquery From e6ceb6c7c11c9fe2f3bbbc61634adcf442c428d0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 18 Sep 2023 16:17:38 -0500 Subject: [PATCH 112/132] "fix rtd theme " --- docs/conf.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 72546d5..964e471 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -114,19 +114,10 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get("READTHEDOCS", None) == "True" - -if not on_rtd: # only import and set the theme if we're building docs locally - try: - import sphinx_rtd_theme - - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] - except: - html_theme = "default" - html_theme_path = ["."] -else: - html_theme_path = ["."] +import sphinx_rtd_theme + +html_theme = "sphinx_rtd_theme" +html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 09d52ea2820b150b91f4b0239c74ef2529866981 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 31 Oct 2023 20:20:51 -0500 Subject: [PATCH 113/132] remove displayio.Shape usage and replace with vectorio.Rectangle --- .../layouts/grid_layout.py | 51 +++++++------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 5274054..df87eae 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -30,6 +30,7 @@ import math import displayio +from vectorio import Rectangle __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -264,50 +265,40 @@ def _layout_cells(self) -> None: - int(cell["cell_anchor_point"][0] * _measured_width) ) - _horizontal_divider_line = displayio.Shape( - _measured_width + (2 * self.cell_padding), - 1, - mirror_x=False, - mirror_y=False, - ) - - _bottom_divider_tilegrid = displayio.TileGrid( - _horizontal_divider_line, + _bottom_divider_rect = Rectangle( pixel_shader=palette, + width=_measured_width + (2 * self.cell_padding), + height=1, y=_bottom_line_loc_y, x=_bottom_line_loc_x, ) - _top_divider_tilegrid = displayio.TileGrid( - _horizontal_divider_line, + _top_divider_rect = Rectangle( + width=_measured_width + (2 * self.cell_padding), + height=1, pixel_shader=palette, y=_top_line_loc_y, x=_top_line_loc_x, ) - _vertical_divider_line = displayio.Shape( - 1, - _measured_height + (2 * self.cell_padding), - mirror_x=False, - mirror_y=False, - ) - - _left_divider_tilegrid = displayio.TileGrid( - _vertical_divider_line, + _left_divider_rect = Rectangle( pixel_shader=palette, + width=1, + height=_measured_height + (2 * self.cell_padding), y=_top_line_loc_y, x=_top_line_loc_x, ) - _right_divider_tilegrid = displayio.TileGrid( - _vertical_divider_line, + _right_divider_rect = Rectangle( pixel_shader=palette, + width=1, + height=_measured_height + (2 * self.cell_padding), y=_right_line_loc_y, x=_right_line_loc_x, ) for line_obj in self._divider_lines: - self.remove(line_obj["tilegrid"]) + self.remove(line_obj["rect"]) """ Only use bottom divider lines on the bottom row. All @@ -324,8 +315,7 @@ def _layout_cells(self) -> None: ): self._divider_lines.append( { - "shape": _horizontal_divider_line, - "tilegrid": _bottom_divider_tilegrid, + "rect": _bottom_divider_rect, } ) @@ -336,8 +326,7 @@ def _layout_cells(self) -> None: if grid_position_y in self.h_divider_line_rows: self._divider_lines.append( { - "shape": _horizontal_divider_line, - "tilegrid": _top_divider_tilegrid, + "rect": _top_divider_rect, } ) @@ -348,8 +337,7 @@ def _layout_cells(self) -> None: if grid_position_x in self.v_divider_line_cols: self._divider_lines.append( { - "shape": _horizontal_divider_line, - "tilegrid": _left_divider_tilegrid, + "rect": _left_divider_rect, } ) """ @@ -367,13 +355,12 @@ def _layout_cells(self) -> None: ): self._divider_lines.append( { - "shape": _vertical_divider_line, - "tilegrid": _right_divider_tilegrid, + "rect": _right_divider_rect, } ) for line_obj in self._divider_lines: - self.append(line_obj["tilegrid"]) + self.append(line_obj["rect"]) def add_content( self, From 37e4576048482ae0c6cf6e0b741b303fb6c8522a Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Thu, 2 Nov 2023 01:21:01 -0400 Subject: [PATCH 114/132] Replace depreciated .show() --- adafruit_displayio_layout/widgets/cartesian.py | 4 ++-- adafruit_displayio_layout/widgets/switch_round.py | 4 ++-- adafruit_displayio_layout/widgets/widget.py | 2 +- examples/displayio_layout_cartesian_advanced_test.py | 2 +- examples/displayio_layout_cartesian_lineplot.py | 2 +- examples/displayio_layout_cartesian_simpletest.py | 2 +- examples/displayio_layout_flip_input_simpletest.py | 2 +- examples/displayio_layout_grid_layout_get_cell_test.py | 2 +- examples/displayio_layout_gridlayout_dividers.py | 2 +- .../displayio_layout_gridlayout_pygame_display_simpletest.py | 2 +- examples/displayio_layout_gridlayout_simpletest.py | 2 +- examples/displayio_layout_icon_animated_simpletest.py | 2 +- examples/displayio_layout_page_layout_advancedtest.py | 2 +- examples/displayio_layout_page_layout_simpletest.py | 2 +- examples/displayio_layout_pygame_display_switch_round.py | 2 +- examples/displayio_layout_simpletest.py | 2 +- examples/displayio_layout_switch_multiple.py | 2 +- examples/displayio_layout_switch_simpletest.py | 2 +- examples/displayio_layout_tab_layout_simpletest.py | 2 +- examples/displayio_layout_tab_layout_touchtest.py | 2 +- .../hotplug_sensor_examples/displayio_layout_hotplug_rtc.py | 2 +- .../displayio_layout_hotplug_temp_sensor.py | 2 +- 22 files changed, 24 insertions(+), 24 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index d47722e..bcb11dc 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -98,7 +98,7 @@ class Cartesian(Widget): .. code-block:: python - display.show(my_plane) # add the group to the display + display.root_group = my_plane # add the group to the display If you want to have multiple display elements, you can create a group and then append the plane and the other elements to the group. Then, you can add the full @@ -114,7 +114,7 @@ class Cartesian(Widget): # Append other display elements to the group # - display.show(my_group) # add the group to the display + display.root_group = my_group # add the group to the display **Summary: Cartesian Features and input variables** diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index 78a4cd7..e583b18 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -148,7 +148,7 @@ class SwitchRound(Widget, Control): .. code-block:: python - display.show(my_switch) # add the group to the display + display.root_group = my_switch # add the group to the display If you want to have multiple display elements, you can create a group and then append the switch and the other elements to the group. Then, you can add the full @@ -164,7 +164,7 @@ class SwitchRound(Widget, Control): # Append other display elements to the group # - display.show(my_group) # add the group to the display + display.root_group = my_group # add the group to the display For a full example, including how to respond to screen touches, check out the following examples in the `Adafruit_CircuitPython_DisplayIO_Layout diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index 6bf6dc6..7a376f1 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -122,7 +122,7 @@ class Widget(displayio.Group): The Widget class has several options for setting the widget position on the screen. In the simplest case, you can define the widget's *.x* and *.y* properties to set the position. (**Reminder**: If your widget is directly shown by the display using - *display.show(my_widget)*), then the *.x* and *.y* positions will be in the display's + *display.root_group=my_widget*), then the *.x* and *.y* positions will be in the display's coordinate system. But if your widget is held inside of another Group, then its coordinates will be in that Group's coordinate system.) diff --git a/examples/displayio_layout_cartesian_advanced_test.py b/examples/displayio_layout_cartesian_advanced_test.py index 9d3ccbc..e10a765 100644 --- a/examples/displayio_layout_cartesian_advanced_test.py +++ b/examples/displayio_layout_cartesian_advanced_test.py @@ -69,7 +69,7 @@ ) my_group.append(car5) -display.show(my_group) +display.root_group = my_group while True: pass diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index 5725f39..14683a0 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -30,7 +30,7 @@ my_group = displayio.Group() my_group.append(my_plane) -display.show(my_group) # add high level Group to the display +display.root_group = my_group # add high level Group to the display data = [ # (0, 0), # we do this point manually - so we have no wait... diff --git a/examples/displayio_layout_cartesian_simpletest.py b/examples/displayio_layout_cartesian_simpletest.py index 3eb604a..e859380 100644 --- a/examples/displayio_layout_cartesian_simpletest.py +++ b/examples/displayio_layout_cartesian_simpletest.py @@ -37,7 +37,7 @@ my_group = displayio.Group() my_group.append(my_plane) -display.show(my_group) # add high level Group to the display +display.root_group = my_group # add high level Group to the display posx = 0 posy = 0 diff --git a/examples/displayio_layout_flip_input_simpletest.py b/examples/displayio_layout_flip_input_simpletest.py index ed46952..c51c00d 100755 --- a/examples/displayio_layout_flip_input_simpletest.py +++ b/examples/displayio_layout_flip_input_simpletest.py @@ -97,7 +97,7 @@ my_group.append(my_flip2) my_group.append(my_flip3) -display.show(my_group) # add high level Group to the display +display.root_group = my_group # add high level Group to the display display.auto_refresh = True while True: diff --git a/examples/displayio_layout_grid_layout_get_cell_test.py b/examples/displayio_layout_grid_layout_get_cell_test.py index a9b812d..9e6d674 100644 --- a/examples/displayio_layout_grid_layout_get_cell_test.py +++ b/examples/displayio_layout_grid_layout_get_cell_test.py @@ -18,7 +18,7 @@ # Make the display context main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group layout = GridLayout( x=10, diff --git a/examples/displayio_layout_gridlayout_dividers.py b/examples/displayio_layout_gridlayout_dividers.py index f649562..d7cefab 100644 --- a/examples/displayio_layout_gridlayout_dividers.py +++ b/examples/displayio_layout_gridlayout_dividers.py @@ -17,7 +17,7 @@ # Make the display context main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group layout = GridLayout( x=10, diff --git a/examples/displayio_layout_gridlayout_pygame_display_simpletest.py b/examples/displayio_layout_gridlayout_pygame_display_simpletest.py index 207faf8..15fa6d9 100644 --- a/examples/displayio_layout_gridlayout_pygame_display_simpletest.py +++ b/examples/displayio_layout_gridlayout_pygame_display_simpletest.py @@ -18,7 +18,7 @@ display = PyGameDisplay(width=320, height=240) main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group layout = GridLayout( x=10, diff --git a/examples/displayio_layout_gridlayout_simpletest.py b/examples/displayio_layout_gridlayout_simpletest.py index 98e9578..0816dd7 100644 --- a/examples/displayio_layout_gridlayout_simpletest.py +++ b/examples/displayio_layout_gridlayout_simpletest.py @@ -18,7 +18,7 @@ # Make the display context main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group layout = GridLayout( x=10, diff --git a/examples/displayio_layout_icon_animated_simpletest.py b/examples/displayio_layout_icon_animated_simpletest.py index 32b6aaa..c8cb37a 100644 --- a/examples/displayio_layout_icon_animated_simpletest.py +++ b/examples/displayio_layout_icon_animated_simpletest.py @@ -52,7 +52,7 @@ main_group.append(icon_zoom) main_group.append(icon_shrink) -display.show(main_group) +display.root_group = main_group COOLDOWN_TIME = 0.25 diff --git a/examples/displayio_layout_page_layout_advancedtest.py b/examples/displayio_layout_page_layout_advancedtest.py index fa5a4ca..9a6bde8 100644 --- a/examples/displayio_layout_page_layout_advancedtest.py +++ b/examples/displayio_layout_page_layout_advancedtest.py @@ -19,7 +19,7 @@ # create and show main_group main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group # create the page layout test_page_layout = PageLayout(x=0, y=0) diff --git a/examples/displayio_layout_page_layout_simpletest.py b/examples/displayio_layout_page_layout_simpletest.py index 15fcf97..b11c02c 100644 --- a/examples/displayio_layout_page_layout_simpletest.py +++ b/examples/displayio_layout_page_layout_simpletest.py @@ -18,7 +18,7 @@ # create and show main_group main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group # create the page layout test_page_layout = PageLayout(x=0, y=0) diff --git a/examples/displayio_layout_pygame_display_switch_round.py b/examples/displayio_layout_pygame_display_switch_round.py index addf09b..c21111b 100644 --- a/examples/displayio_layout_pygame_display_switch_round.py +++ b/examples/displayio_layout_pygame_display_switch_round.py @@ -18,7 +18,7 @@ # Make the display context main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group switch_x = 30 switch_y = 30 diff --git a/examples/displayio_layout_simpletest.py b/examples/displayio_layout_simpletest.py index 818bcb8..16b3bb4 100644 --- a/examples/displayio_layout_simpletest.py +++ b/examples/displayio_layout_simpletest.py @@ -20,7 +20,7 @@ # Make the display context main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group layout = GridLayout( x=10, diff --git a/examples/displayio_layout_switch_multiple.py b/examples/displayio_layout_switch_multiple.py index 5e09289..6cb1bab 100755 --- a/examples/displayio_layout_switch_multiple.py +++ b/examples/displayio_layout_switch_multiple.py @@ -102,7 +102,7 @@ my_group.append(my_switch8) # Add my_group to the display -display.show(my_group) +display.root_group = my_group # Start the main loop diff --git a/examples/displayio_layout_switch_simpletest.py b/examples/displayio_layout_switch_simpletest.py index 46ae7e2..a9cfbc8 100644 --- a/examples/displayio_layout_switch_simpletest.py +++ b/examples/displayio_layout_switch_simpletest.py @@ -30,7 +30,7 @@ my_group.append(my_switch) # Add my_group to the display -display.show(my_group) +display.root_group = my_group # Start the main loop while True: diff --git a/examples/displayio_layout_tab_layout_simpletest.py b/examples/displayio_layout_tab_layout_simpletest.py index 20ad427..188cd75 100644 --- a/examples/displayio_layout_tab_layout_simpletest.py +++ b/examples/displayio_layout_tab_layout_simpletest.py @@ -21,7 +21,7 @@ # create and show main_group main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group font = terminalio.FONT diff --git a/examples/displayio_layout_tab_layout_touchtest.py b/examples/displayio_layout_tab_layout_touchtest.py index 47c5cbd..e8fe6ee 100644 --- a/examples/displayio_layout_tab_layout_touchtest.py +++ b/examples/displayio_layout_tab_layout_touchtest.py @@ -34,7 +34,7 @@ # create and show main_group main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group font = terminalio.FONT diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py index 757d105..041bbcf 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py @@ -222,7 +222,7 @@ def list(self): # create and show main_group main_group = displayio.Group() -display.show(main_group) +display.root_group = main_group # fon.gvars bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") font_arial = bitmap_font.load_font("/fonts/Arial-16.bdf") diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py index e420995..6ec1cb1 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py @@ -453,7 +453,7 @@ def refresh_from_NTP(): # create and show main_group main_group = displayio.Group() # The Main Display Group -display.show(main_group) +display.root_group = main_group # font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf") font_arial = bitmap_font.load_font("/fonts/Arial-16.bdf") From f5a8f6a19c1ced3c53799daf63b7a870b72ad364 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 16 Oct 2023 14:30:31 -0500 Subject: [PATCH 115/132] unpin sphinx and add sphinx-rtd-theme to docs reqs Signed-off-by: foamyguy --- docs/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 797aa04..979f568 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,5 +2,6 @@ # # SPDX-License-Identifier: Unlicense -sphinx>=4.0.0 +sphinx sphinxcontrib-jquery +sphinx-rtd-theme From 53b190e3f836516250dc5e1e33cda01a45efa181 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 16 Dec 2023 11:47:03 -0600 Subject: [PATCH 116/132] GridLayout cell contains --- .../layouts/grid_layout.py | 49 +++++++++++++++++++ docs/conf.py | 1 + 2 files changed, 50 insertions(+) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index df87eae..eee392d 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -406,9 +406,21 @@ def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: :return: the displayio content object at those coordinates """ for index, cell in enumerate(self._cell_content_list): + # exact location 1x1 cell if cell["grid_position"] == cell_coordinates: return self._cell_content_list[index]["content"] + # multi-spanning cell, any size bigger than 1x1 + if ( + cell["grid_position"][0] + <= cell_coordinates[0] + < cell["grid_position"][0] + cell["cell_size"][0] + and cell["grid_position"][1] + <= cell_coordinates[1] + < cell["grid_position"][1] + cell["cell_size"][1] + ): + return self._cell_content_list[index]["content"] + raise KeyError( "GridLayout does not contain cell at coordinates {}".format( cell_coordinates @@ -425,3 +437,40 @@ def cell_size_pixels(self) -> Tuple[int, int]: pixels of a 1x1 cell in the GridLayout """ return (self._width // self.grid_size[0], self._height // self.grid_size[1]) + + @property + def width(self) -> int: + """ + The width in pixels of the GridLayout. + """ + return self._width + + @property + def height(self) -> int: + """ + The width in pixels of the GridLayout. + """ + return self._height + + def which_cell_contains( + self, pixel_location: Union[Tuple[int, int], List[int]] + ) -> Optional[tuple]: + """ + Given a pixel x,y coordinate returns the location of the cell + that contains the coordinate. + + :param pixel_location: x,y pixel coordinate as a tuple or list + :returns: cell coordinates x,y tuple or None if the pixel coordinates are + outside the bounds of the GridLayout + """ + cell_size = self.cell_size_pixels + if ( + not self.x <= pixel_location[0] < self.x + self.width + or not self.y <= pixel_location[1] < self.y + self.height + ): + return None + + cell_x_coord = (pixel_location[0] - self.x) // cell_size[0] + cell_y_coord = (pixel_location[1] - self.y) // cell_size[1] + + return cell_x_coord, cell_y_coord diff --git a/docs/conf.py b/docs/conf.py index 964e471..3d12838 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,6 +32,7 @@ # autodoc module docs will fail to generate with a warning. autodoc_mock_imports = [ "vectorio", + "terminalio", "bitmaptools", ] From 4b0f993ff57eb0c04e67ae49e8fb6d7efe595696 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 16 Dec 2023 11:51:22 -0600 Subject: [PATCH 117/132] fix docstring --- adafruit_displayio_layout/layouts/grid_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index eee392d..b57ad24 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -448,7 +448,7 @@ def width(self) -> int: @property def height(self) -> int: """ - The width in pixels of the GridLayout. + The height in pixels of the GridLayout. """ return self._height From 873672f83bcb1e60ab7cbf8ac1b8d9f149bc9a28 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 26 Dec 2023 15:07:16 -0600 Subject: [PATCH 118/132] public layout_content. Don't add and remove lines many times unecessarily. --- .../layouts/grid_layout.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index b57ad24..d43608a 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -111,8 +111,13 @@ def __init__( ): self.cell_padding = 1 + def layout_cells(self): + self._layout_cells() + def _layout_cells(self) -> None: # pylint: disable=too-many-locals, too-many-branches, too-many-statements + for line_obj in self._divider_lines: + self.remove(line_obj["rect"]) for cell in self._cell_content_list: if cell["content"] not in self: grid_size_x = self.grid_size[0] @@ -359,15 +364,16 @@ def _layout_cells(self) -> None: } ) - for line_obj in self._divider_lines: - self.append(line_obj["rect"]) + for line_obj in self._divider_lines: + self.append(line_obj["rect"]) def add_content( - self, - cell_content: displayio.Group, - grid_position: Tuple[int, int], - cell_size: Tuple[int, int], - cell_anchor_point: Optional[Tuple[float, ...]] = None, + self, + cell_content: displayio.Group, + grid_position: Tuple[int, int], + cell_size: Tuple[int, int], + cell_anchor_point: Optional[Tuple[float, ...]] = None, + layout_cells=True ) -> None: """Add a child to the grid. @@ -395,7 +401,8 @@ def add_content( "cell_size": cell_size, } self._cell_content_list.append(sub_view_obj) - self._layout_cells() + if layout_cells: + self._layout_cells() def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: """ From 67f8bc959090076bc53b427745b5426bc452d6fd Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 26 Dec 2023 17:48:35 -0600 Subject: [PATCH 119/132] public layout_content. Don't add and remove lines many times unecessarily. --- adafruit_displayio_layout/layouts/grid_layout.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index b57ad24..27dc5db 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -111,8 +111,14 @@ def __init__( ): self.cell_padding = 1 + def layout_cells(self): + """render the grid with all cell content and dividers""" + self._layout_cells() + def _layout_cells(self) -> None: # pylint: disable=too-many-locals, too-many-branches, too-many-statements + for line_obj in self._divider_lines: + self.remove(line_obj["rect"]) for cell in self._cell_content_list: if cell["content"] not in self: grid_size_x = self.grid_size[0] @@ -359,8 +365,8 @@ def _layout_cells(self) -> None: } ) - for line_obj in self._divider_lines: - self.append(line_obj["rect"]) + for line_obj in self._divider_lines: + self.append(line_obj["rect"]) def add_content( self, @@ -368,6 +374,7 @@ def add_content( grid_position: Tuple[int, int], cell_size: Tuple[int, int], cell_anchor_point: Optional[Tuple[float, ...]] = None, + layout_cells=True, ) -> None: """Add a child to the grid. @@ -395,7 +402,8 @@ def add_content( "cell_size": cell_size, } self._cell_content_list.append(sub_view_obj) - self._layout_cells() + if layout_cells: + self._layout_cells() def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: """ From baeccd1eed05556d690d5e5eed5a346ee8346c30 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 16 Jan 2024 15:46:40 -0600 Subject: [PATCH 120/132] fix extra divider line removal --- adafruit_displayio_layout/layouts/grid_layout.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 27dc5db..fd06895 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -303,9 +303,6 @@ def _layout_cells(self) -> None: x=_right_line_loc_x, ) - for line_obj in self._divider_lines: - self.remove(line_obj["rect"]) - """ Only use bottom divider lines on the bottom row. All other rows rely on top divder lines of the row beneath them. From c5441369e34873d4bc6dfa1b7e5d78d5ad5cac50 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 7 Oct 2024 09:24:05 -0500 Subject: [PATCH 121/132] remove deprecated get_html_theme_path() call Signed-off-by: foamyguy --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 3d12838..a314186 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -118,7 +118,6 @@ import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 40b1812db0fd1d359e70b9215ece75aa9a78e635 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 14 Nov 2024 16:14:45 -0600 Subject: [PATCH 122/132] adding linear_layout --- .../layouts/linear_layout.py | 151 ++++++++++++++++++ ...isplayio_layout_linearlayout_simpletest.py | 37 +++++ 2 files changed, 188 insertions(+) create mode 100644 adafruit_displayio_layout/layouts/linear_layout.py create mode 100644 examples/displayio_layout_linearlayout_simpletest.py diff --git a/adafruit_displayio_layout/layouts/linear_layout.py b/adafruit_displayio_layout/layouts/linear_layout.py new file mode 100644 index 0000000..be48f70 --- /dev/null +++ b/adafruit_displayio_layout/layouts/linear_layout.py @@ -0,0 +1,151 @@ +# SPDX-FileCopyrightText: Copyright (c) 2021 Tim Cocks +# +# SPDX-License-Identifier: MIT +""" +`grid_layout` +================================================================================ + +A layout that organizes cells into a vertical or horizontal line. + + +* Author(s): Tim Cocks + +Implementation Notes +-------------------- + +**Hardware:** + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://github.com/adafruit/circuitpython/releases + +""" + +from adafruit_displayio_layout.widgets.widget import Widget + + +class LinearLayout(Widget): + """ + LinearLayout holds multiple content elements and arranges + them in a line either horizontally or vertically. + """ + + VERTICAL_ORIENTATION = 1 + HORIZONTAL_ORIENTATION = 2 + + def __init__( + self, + x, + y, + orientation=VERTICAL_ORIENTATION, + padding=0, + ): + """ + :param int x: The horizontal position of the layout + :param int y: The vertical position of the layout + :param int orientation: The orientation of the layout. Must be VERTICAL_ORIENTATION + or HORIZONTAL_ORIENTATION + :param int padding: The padding between items in the layout + """ + + super().__init__(x=x, y=y, width=1, height=1) + + self.x = x + self.y = y + self.padding = padding + if orientation not in [self.VERTICAL_ORIENTATION, self.HORIZONTAL_ORIENTATION]: + raise ValueError( + "Orientation must be either LinearLayout.VERTICAL_ORIENTATION" + " or LinearLayout.HORIZONTAL_ORIENTATION" + ) + + self.orientation = orientation + self._content_list = [] + self._prev_content_end = 0 + + def add_content(self, content): + """Add a child to the linear layout. + + :param content: the content to add to the linear layout e.g. label, button, etc... + Group subclasses that have width and height properties can be used. + + :return: None""" + + self._content_list.append(content) + self.append(content) + self._layout() + + def _layout(self): + # pylint: disable=too-many-branches, protected-access + self._prev_content_end = 0 + + for _, content in enumerate(self._content_list): + if not hasattr(content, "anchor_point"): + if self.orientation == self.VERTICAL_ORIENTATION: + content.y = self._prev_content_end + try: + self._prev_content_end = ( + self._prev_content_end + content.height + self.padding + ) + except AttributeError as error: + print(error) + try: + self._prev_content_end = ( + self._prev_content_end + content._height + self.padding + ) + except AttributeError as inner_error: + print(inner_error) + + else: + content.x = self._prev_content_end + if not hasattr(content, "tile_width"): + self._prev_content_end = ( + content.x + content.width + (self.padding * 2) + ) + else: + self._prev_content_end = ( + content.x + + (content.width * content.tile_width) + + (self.padding * 2) + ) + else: # use anchor point + content.anchor_point = ( + 0, + content.anchor_point[1] if content.anchor_point is not None else 0, + ) + if self.orientation == self.VERTICAL_ORIENTATION: + content.anchored_position = (0, self._prev_content_end) + # self._prev_content_end = content.y + content.height + if not hasattr(content, "bounding_box"): + self._prev_content_end = ( + self._prev_content_end + content.height + self.padding + ) + else: + self._prev_content_end = ( + self._prev_content_end + + (content.bounding_box[3] * content.scale) + + self.padding + ) + + else: + original_achored_pos_y = ( + content.anchored_position[1] + if content.anchored_position is not None + else 0 + ) + + content.anchored_position = ( + self._prev_content_end, + original_achored_pos_y, + ) + if not hasattr(content, "bounding_box"): + self._prev_content_end = ( + self._prev_content_end + content.width + self.padding + ) + else: + self._prev_content_end = ( + self._prev_content_end + + (content.bounding_box[2] * content.scale) + + self.padding + ) diff --git a/examples/displayio_layout_linearlayout_simpletest.py b/examples/displayio_layout_linearlayout_simpletest.py new file mode 100644 index 0000000..4090561 --- /dev/null +++ b/examples/displayio_layout_linearlayout_simpletest.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2024 Tim C, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Illustrates usage of LinearLayout to display a text label to the right of +an icon. +""" +import adafruit_imageload +import board +import displayio +import terminalio +from adafruit_display_text import label +from adafruit_displayio_layout.layouts.linear_layout import LinearLayout + +# use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.) +# see guide for setting up external displays (TFT / OLED breakouts, RGB matrices, etc.) +# https://learn.adafruit.com/circuitpython-display-support-using-displayio/display-and-display-bus +display = board.DISPLAY + +# Make the display context +main_group = displayio.Group() +display.root_group = main_group + +layout = LinearLayout( + x=10, y=10, padding=4, orientation=LinearLayout.HORIZONTAL_ORIENTATION +) + +lbl = label.Label(terminalio.FONT, scale=4, x=0, y=0, text="Hello") + +icon, icon_palette = adafruit_imageload.load("icons/Play_48x48_small.bmp") +icon_tile_grid = displayio.TileGrid(icon, pixel_shader=icon_palette) +layout.add_content(icon_tile_grid) +layout.add_content(lbl) + +main_group.append(layout) +while True: + pass From 5ab4c305be0f50269dda186197a9b788eda9821d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 14 Nov 2024 16:22:38 -0600 Subject: [PATCH 123/132] fix docstring --- adafruit_displayio_layout/layouts/linear_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_displayio_layout/layouts/linear_layout.py b/adafruit_displayio_layout/layouts/linear_layout.py index be48f70..3bcd6cb 100644 --- a/adafruit_displayio_layout/layouts/linear_layout.py +++ b/adafruit_displayio_layout/layouts/linear_layout.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: MIT """ -`grid_layout` +`linear_layout` ================================================================================ A layout that organizes cells into a vertical or horizontal line. From a89687597e929bcb65c6ae1c5ae5cea3d0179b80 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jan 2025 11:32:34 -0600 Subject: [PATCH 124/132] add sphinx configuration to rtd.yaml Signed-off-by: foamyguy --- .readthedocs.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c8e145a..3ed8fb5 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,9 @@ # Required version: 2 +sphinx: + configuration: docs/conf.py + build: os: ubuntu-20.04 tools: From fe5de40916d96e7c9cbc7c4e52c754572c921e1a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 24 Feb 2025 17:27:35 -0600 Subject: [PATCH 125/132] use ruff and remove 8x displayio code --- .gitattributes | 11 + .pre-commit-config.yaml | 43 +- .pylintrc | 399 ------------------ README.rst | 6 +- .../layouts/grid_layout.py | 29 +- .../layouts/linear_layout.py | 15 +- .../layouts/page_layout.py | 30 +- .../layouts/tab_layout.py | 34 +- .../widgets/cartesian.py | 100 ++--- adafruit_displayio_layout/widgets/control.py | 2 - adafruit_displayio_layout/widgets/easing.py | 6 +- .../widgets/flip_input.py | 170 +++----- .../widgets/icon_animated.py | 29 +- .../widgets/icon_widget.py | 15 +- .../widgets/switch_round.py | 39 +- adafruit_displayio_layout/widgets/widget.py | 2 - docs/api.rst | 3 + docs/conf.py | 8 +- ...isplayio_layout_cartesian_advanced_test.py | 1 + .../displayio_layout_cartesian_lineplot.py | 2 + .../displayio_layout_cartesian_simpletest.py | 2 + .../displayio_layout_flip_input_simpletest.py | 10 +- ...playio_layout_grid_layout_get_cell_test.py | 10 +- .../displayio_layout_gridlayout_dividers.py | 10 +- ...ut_gridlayout_pygame_display_simpletest.py | 10 +- .../displayio_layout_gridlayout_simpletest.py | 10 +- ...splayio_layout_icon_animated_simpletest.py | 9 +- ...isplayio_layout_linearlayout_simpletest.py | 6 +- ...splayio_layout_page_layout_advancedtest.py | 17 +- ...displayio_layout_page_layout_simpletest.py | 9 +- ...ayio_layout_pygame_display_switch_round.py | 3 +- examples/displayio_layout_simpletest.py | 10 +- examples/displayio_layout_switch_multiple.py | 4 +- .../displayio_layout_switch_simpletest.py | 4 +- .../displayio_layout_tab_layout_simpletest.py | 17 +- .../displayio_layout_tab_layout_touchtest.py | 10 +- .../displayio_layout_hotplug_rtc.py | 62 ++- .../displayio_layout_hotplug_temp_sensor.py | 74 ++-- ruff.toml | 101 +++++ 39 files changed, 403 insertions(+), 919 deletions(-) create mode 100644 .gitattributes delete mode 100644 .pylintrc create mode 100644 ruff.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..21c125c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +.py text eol=lf +.rst text eol=lf +.txt text eol=lf +.yaml text eol=lf +.toml text eol=lf +.license text eol=lf +.md text eol=lf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 70ade69..ff19dde 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,42 +1,21 @@ -# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries # # SPDX-License-Identifier: Unlicense repos: - - repo: https://github.com/python/black - rev: 23.3.0 - hooks: - - id: black - - repo: https://github.com/fsfe/reuse-tool - rev: v1.1.2 - hooks: - - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/pycqa/pylint - rev: v2.17.4 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.4 hooks: - - id: pylint - name: pylint (library code) - types: [python] - args: - - --disable=consider-using-f-string - exclude: "^(docs/|examples/|tests/|setup.py$)" - - id: pylint - name: pylint (example code) - description: Run pylint rules on "examples/*.py" files - types: [python] - files: "^examples/" - args: - - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code - - id: pylint - name: pylint (test code) - description: Run pylint rules on "tests/*.py" files - types: [python] - files: "^tests/" - args: - - --disable=missing-docstring,consider-using-f-string,duplicate-code + - id: ruff-format + - id: ruff + args: ["--fix"] + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.1 + hooks: + - id: reuse diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index f945e92..0000000 --- a/.pylintrc +++ /dev/null @@ -1,399 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# -# SPDX-License-Identifier: Unlicense - -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Add files or directories to the ignore-list. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the ignore-list. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins=pylint.extensions.no_self_use - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call -disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -# notes=FIXME,XXX,TODO -notes=FIXME,XXX - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=board - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -# expected-line-ending-format= -expected-line-ending-format=LF - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=yes - -# Minimum lines number of a similarity. -min-similarity-lines=12 - - -[BASIC] - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class names -# class-rgx=[A-Z_][a-zA-Z0-9]+$ -class-rgx=[A-Z_][a-zA-Z0-9_]+$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -# good-names=i,j,k,ex,Run,_ -good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Maximum number of attributes for a class (see R0902). -# max-attributes=7 -max-attributes=11 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=1 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=builtins.Exception diff --git a/README.rst b/README.rst index a797fcd..b9628db 100644 --- a/README.rst +++ b/README.rst @@ -13,9 +13,9 @@ Introduction :target: https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout/actions :alt: Build Status -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code Style: Black +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Code Style: Ruff CircuitPython helper library for displayio layouts and widgets. diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index fd06895..5d2be9b 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -22,6 +22,7 @@ https://github.com/adafruit/circuitpython/releases """ + try: # Used only for typing from typing import Any, List, Optional, Tuple, Union @@ -29,6 +30,7 @@ pass import math + import displayio from vectorio import Rectangle @@ -58,8 +60,6 @@ class GridLayout(displayio.Group): """ - # pylint: disable=too-many-arguments - # pylint: disable=too-many-instance-attributes def __init__( self, x: int, @@ -106,9 +106,7 @@ def __init__( self.v_divider_line_cols.append(_x) # use at least 1 padding so that content is inside the divider lines - if cell_padding == 0 and ( - divider_lines or h_divider_line_rows or v_divider_line_cols - ): + if cell_padding == 0 and (divider_lines or h_divider_line_rows or v_divider_line_cols): self.cell_padding = 1 def layout_cells(self): @@ -116,7 +114,6 @@ def layout_cells(self): self._layout_cells() def _layout_cells(self) -> None: - # pylint: disable=too-many-locals, too-many-branches, too-many-statements for line_obj in self._divider_lines: self.remove(line_obj["rect"]) for cell in self._cell_content_list: @@ -310,11 +307,8 @@ def _layout_cells(self) -> None: areas larger than 1x1 cells. For 1x1 cells this will equal zero and not change anything. """ - if ( - grid_position_y + content_cell_size_y - 1 - ) == grid_size_y - 1 and ( - (grid_position_y + content_cell_size_y - 1) + 1 - in self.h_divider_line_rows + if (grid_position_y + content_cell_size_y - 1) == grid_size_y - 1 and ( + (grid_position_y + content_cell_size_y - 1) + 1 in self.h_divider_line_rows ): self._divider_lines.append( { @@ -350,11 +344,8 @@ def _layout_cells(self) -> None: areas larger than 1x1 cells. For 1x1 cells this will equal zero and not change anything. """ - if ( - grid_position_x + content_cell_size_x - 1 - ) == grid_size_x - 1 and ( - (grid_position_x + content_cell_size_x - 1) + 1 - in self.v_divider_line_cols + if (grid_position_x + content_cell_size_x - 1) == grid_size_x - 1 and ( + (grid_position_x + content_cell_size_x - 1) + 1 in self.v_divider_line_cols ): self._divider_lines.append( { @@ -426,11 +417,7 @@ def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: ): return self._cell_content_list[index]["content"] - raise KeyError( - "GridLayout does not contain cell at coordinates {}".format( - cell_coordinates - ) - ) + raise KeyError(f"GridLayout does not contain cell at coordinates {cell_coordinates}") @property def cell_size_pixels(self) -> Tuple[int, int]: diff --git a/adafruit_displayio_layout/layouts/linear_layout.py b/adafruit_displayio_layout/layouts/linear_layout.py index 3bcd6cb..9815300 100644 --- a/adafruit_displayio_layout/layouts/linear_layout.py +++ b/adafruit_displayio_layout/layouts/linear_layout.py @@ -54,7 +54,7 @@ def __init__( self.x = x self.y = y self.padding = padding - if orientation not in [self.VERTICAL_ORIENTATION, self.HORIZONTAL_ORIENTATION]: + if orientation not in {self.VERTICAL_ORIENTATION, self.HORIZONTAL_ORIENTATION}: raise ValueError( "Orientation must be either LinearLayout.VERTICAL_ORIENTATION" " or LinearLayout.HORIZONTAL_ORIENTATION" @@ -77,7 +77,6 @@ def add_content(self, content): self._layout() def _layout(self): - # pylint: disable=too-many-branches, protected-access self._prev_content_end = 0 for _, content in enumerate(self._content_list): @@ -100,14 +99,10 @@ def _layout(self): else: content.x = self._prev_content_end if not hasattr(content, "tile_width"): - self._prev_content_end = ( - content.x + content.width + (self.padding * 2) - ) + self._prev_content_end = content.x + content.width + (self.padding * 2) else: self._prev_content_end = ( - content.x - + (content.width * content.tile_width) - + (self.padding * 2) + content.x + (content.width * content.tile_width) + (self.padding * 2) ) else: # use anchor point content.anchor_point = ( @@ -130,9 +125,7 @@ def _layout(self): else: original_achored_pos_y = ( - content.anchored_position[1] - if content.anchored_position is not None - else 0 + content.anchored_position[1] if content.anchored_position is not None else 0 ) content.anchored_position = ( diff --git a/adafruit_displayio_layout/layouts/page_layout.py b/adafruit_displayio_layout/layouts/page_layout.py index 040ccbd..8e69c63 100644 --- a/adafruit_displayio_layout/layouts/page_layout.py +++ b/adafruit_displayio_layout/layouts/page_layout.py @@ -22,9 +22,9 @@ https://github.com/adafruit/circuitpython/releases """ + try: # Used only for typing - # pylint: disable=unused-import from typing import Tuple except ImportError: @@ -90,16 +90,12 @@ def _check_args(self, page_name, page_index): raise AttributeError("Must pass either page_name or page_index") if page_index is not None and page_name is not None: - raise AttributeError( - "Must pass either page_name or page_index only one or the other" - ) + raise AttributeError("Must pass either page_name or page_index only one or the other") if page_index is not None: if page_index >= len(self.page_content_list): raise KeyError( - "KeyError at index {} in list length {}".format( - page_index, len(self.page_content_list) - ), + f"KeyError at index {page_index} in list length {len(self.page_content_list)}", ) if page_name is not None: @@ -110,7 +106,7 @@ def _check_args(self, page_name, page_index): _found = True if not _found: - raise KeyError("Page with name {} not found".format(page_name)) + raise KeyError(f"Page with name {page_name} not found") def get_page(self, page_name=None, page_index=None): """ @@ -133,9 +129,7 @@ def get_page(self, page_name=None, page_index=None): return cell raise KeyError( - "PageLayout does not contain page: {}".format( - page_index if page_index else page_name - ) + f"PageLayout does not contain page: {page_index if page_index else page_name}" ) def show_page(self, page_name=None, page_index=None): @@ -205,11 +199,10 @@ def next_page(self, loop=True): if self._cur_showing_index + 1 < len(self.page_content_list): self.show_page(page_index=self._cur_showing_index + 1) + elif not loop: + print("No more pages") else: - if not loop: - print("No more pages") - else: - self.show_page(page_index=0) + self.show_page(page_index=0) def previous_page(self, loop=True): """ @@ -219,8 +212,7 @@ def previous_page(self, loop=True): """ if self._cur_showing_index - 1 >= 0: self.show_page(page_index=self._cur_showing_index - 1) + elif not loop: + print("No more pages") else: - if not loop: - print("No more pages") - else: - self.show_page(page_index=len(self.page_content_list) - 1) + self.show_page(page_index=len(self.page_content_list) - 1) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index e63f021..ac5875d 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -22,19 +22,22 @@ https://github.com/adafruit/circuitpython/releases """ + try: - from typing import Optional, Union, Tuple - from fontio import BuiltinFont + from typing import Optional, Tuple, Union + from adafruit_bitmap_font.bdf import BDF from adafruit_bitmap_font.pcf import PCF + from fontio import BuiltinFont except ImportError: pass -import terminalio -import displayio import adafruit_imageload +import displayio +import terminalio from adafruit_display_text.bitmap_label import Label from adafruit_imageload.tilegrid_inflator import inflate_tilegrid + from adafruit_displayio_layout.layouts.page_layout import PageLayout __version__ = "0.0.0+auto.0" @@ -68,8 +71,6 @@ class TabLayout(displayio.Group): :param int tab_count: How many tabs to draw in the layout. Positive whole numbers are valid. """ - # pylint: disable=too-many-instance-attributes, too-many-arguments, invalid-name, too-many-branches - def __init__( self, x: int = 0, @@ -86,8 +87,7 @@ def __init__( tab_count: int = None, ): if display is None: - # pylint: disable=import-outside-toplevel - import board + import board # noqa: PLC0415, non-top-level-import if hasattr(board, "DISPLAY"): display = board.DISPLAY @@ -100,9 +100,7 @@ def __init__( super().__init__(x=x, y=y) self.tab_count = tab_count - self._active_bmp, self._active_palette = adafruit_imageload.load( - showing_tab_spritesheet - ) + self._active_bmp, self._active_palette = adafruit_imageload.load(showing_tab_spritesheet) self._inactive_bmp, self._inactive_palette = adafruit_imageload.load( inactive_tab_spritesheet ) @@ -121,9 +119,7 @@ def __init__( for index in inactive_tab_transparent_indexes: self._inactive_palette.make_transparent(index) else: - raise AttributeError( - "inactive_tab_transparent_indexes must be int or tuple" - ) + raise AttributeError("inactive_tab_transparent_indexes must be int or tuple") self.tab_height = self._active_bmp.height self.display = display @@ -147,8 +143,7 @@ def _draw_tabs(self): bmp_obj=self._inactive_bmp, bmp_palette=self._inactive_palette, target_size=( - (self.display.width // self.tab_count) - // (self._active_bmp.width // 3), + (self.display.width // self.tab_count) // (self._active_bmp.width // 3), 3, ), ) @@ -165,8 +160,7 @@ def _draw_tabs(self): _tab_label.anchor_point = (0.5, 0.5) _tab_label.anchored_position = ( - _tab_tilegrid.x - + ((_tab_tilegrid.width * _tab_tilegrid.tile_width) // 2), + _tab_tilegrid.x + ((_tab_tilegrid.width * _tab_tilegrid.tile_width) // 2), (_tab_tilegrid.height * _tab_tilegrid.tile_height) // 2, ) _new_tab_group.append(_tab_label) @@ -282,8 +276,6 @@ def handle_touch_events(self, touch_event): if touch_event: if 0 <= touch_event[1] <= self.tab_height: - touched_tab_index = touch_event[0] // ( - self.display.width // self.tab_count - ) + touched_tab_index = touch_event[0] // (self.display.width // self.tab_count) print(f"{touch_event[0]} - {touched_tab_index}") self.showing_page_index = touched_tab_index diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index bcb11dc..21bbdc8 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -21,13 +21,11 @@ """ -# pylint: disable=too-many-lines, too-many-instance-attributes, too-many-arguments -# pylint: disable=too-many-locals, too-many-statements - import displayio import terminalio -from adafruit_display_text import bitmap_label import vectorio +from adafruit_display_text import bitmap_label + from adafruit_displayio_layout.widgets.widget import Widget try: @@ -229,28 +227,20 @@ def __init__( self._valuey = self.height / 100 self._factory = 100 / (self._yrange[1] - self._yrange[0]) - self._tick_bitmap = displayio.Bitmap( - self._tick_line_thickness, self._tick_line_height, 3 - ) + self._tick_bitmap = displayio.Bitmap(self._tick_line_thickness, self._tick_line_height, 3) self._tick_bitmap.fill(1) self._subticks = subticks axesx_height = ( - 2 - + self._axes_line_thickness - + self._font_height - + self._tick_line_height // 2 + 2 + self._axes_line_thickness + self._font_height + self._tick_line_height // 2 ) self._axesx_bitmap = displayio.Bitmap(self.width, axesx_height, 4) self._axesx_bitmap.fill(0) self._axesy_width = ( - 2 - + self._axes_line_thickness - + self._font_width - + self._tick_line_height // 2 + 2 + self._axes_line_thickness + self._font_width + self._tick_line_height // 2 ) self._axesy_bitmap = displayio.Bitmap(self._axesy_width, self.height, 4) @@ -408,20 +398,14 @@ def _draw_ticks(self) -> None: self._font, color=self._font_color, text=text_tick, - x=-shift_label_x - - self._axes_line_thickness - - self._tick_line_height - - 2, + x=-shift_label_x - self._axes_line_thickness - self._tick_line_height - 2, y=0 + self.height - text_dist, ) self.append(tick_text) bitmaptools.fill_region( self._axesy_bitmap, - self._axesy_width - - self._axes_line_thickness - - self._tick_line_height - - 1, + self._axesy_width - self._axes_line_thickness - self._tick_line_height - 1, text_dist, self._axesy_width - self._axes_line_thickness - 1, text_dist + self._tick_line_thickness, @@ -453,9 +437,7 @@ def _draw_pointers(self, x: int, y: int) -> None: self.append(self._pointer) def _calc_local_xy(self, x: int, y: int) -> Tuple[int, int]: - local_x = ( - int((x - self._xrange[0]) * self._factorx * self._valuex) + self._nudge_x - ) + local_x = int((x - self._xrange[0]) * self._factorx * self._valuex) + self._nudge_x # details on `+ (self.height - 1)` : # the bitmap is set to self.width & self.height # but we are only allowed to draw to pixels 0..height-1 and 0..width-1 @@ -473,9 +455,7 @@ def _check_local_y_in_range(self, local_y: int) -> bool: return 0 <= local_y < self.height def _check_local_xy_in_range(self, local_x: int, local_y: int) -> bool: - return self._check_local_x_in_range(local_x) and self._check_local_y_in_range( - local_y - ) + return self._check_local_x_in_range(local_x) and self._check_local_y_in_range(local_y) def _check_x_in_range(self, x: int) -> bool: return self._xrange[0] <= x <= self._xrange[1] @@ -498,30 +478,16 @@ def _add_point(self, x: int, y: int) -> None: if self._verbose: print("") print( - "xy: ({: >4}, {: >4}) " - "_xrange: ({: >4}, {: >4}) " - "_yrange: ({: >4}, {: >4}) " - "".format( - x, - y, - self._xrange[0], - self._xrange[1], - self._yrange[0], - self._yrange[1], - ) + f"xy: ({x: >4}, {y: >4}) " + f"_xrange: ({self._xrange[0]: >4}, {self._xrange[1]: >4}) " + f"_yrange: ({self._yrange[0]: >4}, {self._yrange[1]: >4}) " + "" ) print( - "local_*: ({: >4}, {: >4}) " - " width: ({: >4}, {: >4}) " - " height: ({: >4}, {: >4}) " - "".format( - local_x, - local_y, - 0, - self.width, - 0, - self.height, - ) + f"local_*: ({local_x: >4}, {local_y: >4}) " + f" width: ({0: >4}, {self.width: >4}) " + f" height: ({0: >4}, {self.height: >4}) " + "" ) if self._check_xy_in_range(x, y): if self._check_local_xy_in_range(local_x, local_y): @@ -536,44 +502,28 @@ def _add_point(self, x: int, y: int) -> None: if not self._check_local_x_in_range(local_x): raise ValueError( "local_x out of range: " - "local_x:{: >4}; _xrange({: >4}, {: >4})" - "".format( - local_x, - 0, - self.width, - ) + f"local_x:{local_x: >4}; _xrange({0: >4}, {self.width: >4})" + "" ) if not self._check_local_y_in_range(local_y): raise ValueError( "local_y out of range: " - "local_y:{: >4}; _yrange({: >4}, {: >4})" - "".format( - local_y, - 0, - self.height, - ) + f"local_y:{local_y: >4}; _yrange({0: >4}, {self.height: >4})" + "" ) else: # for better error messages we check in detail what failed... if not self._check_x_in_range(x): raise ValueError( "x out of range: " - "x:{: >4}; xrange({: >4}, {: >4})" - "".format( - x, - self._xrange[0], - self._xrange[1], - ) + f"x:{x: >4}; xrange({self._xrange[0]: >4}, {self._xrange[1]: >4})" + "" ) if not self._check_y_in_range(y): raise ValueError( "y out of range: " - "y:{: >4}; yrange({: >4}, {: >4})" - "".format( - y, - self._yrange[0], - self._yrange[1], - ) + f"y:{y: >4}; yrange({self._yrange[0]: >4}, {self._yrange[1]: >4})" + "" ) def update_pointer(self, x: int, y: int) -> None: diff --git a/adafruit_displayio_layout/widgets/control.py b/adafruit_displayio_layout/widgets/control.py index f9e5a2b..464804e 100644 --- a/adafruit_displayio_layout/widgets/control.py +++ b/adafruit_displayio_layout/widgets/control.py @@ -30,8 +30,6 @@ __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" -# pylint: disable=unsubscriptable-object, unnecessary-pass - class Control: """A Control class for responsive elements, including touch response functions for displays. diff --git a/adafruit_displayio_layout/widgets/easing.py b/adafruit_displayio_layout/widgets/easing.py index 9a1e9a9..db2d2d0 100644 --- a/adafruit_displayio_layout/widgets/easing.py +++ b/adafruit_displayio_layout/widgets/easing.py @@ -75,7 +75,6 @@ import math - __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" @@ -285,7 +284,7 @@ def exponential_easeinout(pos: float) -> float: """ Easing function for animations: Exponential Ease In & Out """ - if pos in (0.0, 1.0): + if pos in {0.0, 1.0}: return pos if pos < 0.5: return 0.5 * math.pow(2, (20 * pos) - 10) @@ -318,8 +317,7 @@ def elastic_easeinout(pos: float) -> float: if pos < 0.5: return 0.5 * math.sin(13 * math.pi * pos) * math.pow(2, 10 * ((2 * pos) - 1)) return 0.5 * ( - math.sin(-13 * math.pi / 2 * ((2 * pos - 1) + 1)) * pow(2, -10 * (2 * pos - 1)) - + 2 + math.sin(-13 * math.pi / 2 * ((2 * pos - 1) + 1)) * pow(2, -10 * (2 * pos - 1)) + 2 ) diff --git a/adafruit_displayio_layout/widgets/flip_input.py b/adafruit_displayio_layout/widgets/flip_input.py index 1474225..cbdae52 100644 --- a/adafruit_displayio_layout/widgets/flip_input.py +++ b/adafruit_displayio_layout/widgets/flip_input.py @@ -23,20 +23,18 @@ import gc import time -import displayio -from terminalio import FONT +import displayio from adafruit_display_shapes.triangle import Triangle - from adafruit_display_text import bitmap_label -from adafruit_displayio_layout.widgets.widget import Widget -from adafruit_displayio_layout.widgets.control import Control +from terminalio import FONT -# pylint: disable=reimported +from adafruit_displayio_layout.widgets.control import Control # select the two "easing" functions to use for animations from adafruit_displayio_layout.widgets.easing import back_easeinout as easein from adafruit_displayio_layout.widgets.easing import back_easeinout as easeout +from adafruit_displayio_layout.widgets.widget import Widget try: from typing import Any, List, Optional, Tuple @@ -48,10 +46,6 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" -# pylint: disable=too-many-arguments, too-many-branches, too-many-statements -# pylint: disable=too-many-locals, too-many-instance-attributes - - class FlipInput(Widget, Control): """A flip style input selector. The value changes based on touch inputs on the two halves of the indicator with optional arrows added. @@ -121,7 +115,6 @@ def __init__( # initialize the Control superclass - # pylint: disable=bad-super-call super(Control, self).__init__() self.value_list = value_list @@ -157,18 +150,14 @@ def __init__( for i, character in enumerate(this_value): glyph = self._font.get_glyph(ord(character)) - if ( - i == 0 - ): # if it's the first character in the string, check the left value + if i == 0: # if it's the first character in the string, check the left value if left is None: left = glyph.dx else: left = min(left, glyph.dx) if right is None: - right = max( - xposition + glyph.dx + glyph.width, xposition + glyph.shift_x - ) + right = max(xposition + glyph.dx + glyph.width, xposition + glyph.shift_x) else: right = max( right, @@ -189,12 +178,7 @@ def __init__( xposition = xposition + glyph.shift_x # Something is wrong if left, right, top, or bottom are still None here - assert ( - right is not None - and left is not None - and top is not None - and bottom is not None - ) + assert right is not None and left is not None and top is not None and bottom is not None self._bounding_box = [ 0, @@ -226,10 +210,7 @@ def __init__( if horizontal: # horizontal orientation, add arrow padding to x-dimension and # alt_padding to y-dimension self.touch_boundary = ( - self._bounding_box[0] - - self._arrow_gap - - arrow_height - - self._arrow_touch_padding, + self._bounding_box[0] - self._arrow_gap - arrow_height - self._arrow_touch_padding, self._bounding_box[1] - self._alt_touch_padding, self._bounding_box[2] + 2 * (self._arrow_gap + arrow_height + self._arrow_touch_padding), @@ -239,10 +220,7 @@ def __init__( # alt_padding to x-dimension self.touch_boundary = ( self._bounding_box[0] - self._alt_touch_padding, - self._bounding_box[1] - - self._arrow_gap - - arrow_height - - self._arrow_touch_padding, + self._bounding_box[1] - self._arrow_gap - arrow_height - self._arrow_touch_padding, self._bounding_box[2] + 2 * self._alt_touch_padding, self._bounding_box[3] + 2 * (self._arrow_gap + arrow_height + self._arrow_touch_padding), @@ -263,11 +241,7 @@ def __init__( if (arrow_color is not None) or (arrow_outline is not None): if horizontal: # horizontal orientation, add left and right arrows - if ( - (arrow_width is not None) - and (arrow_height is not None) - and (arrow_width > 0) - ): + if (arrow_width is not None) and (arrow_height is not None) and (arrow_width > 0): mid_point_y = self._bounding_box[1] + self._bounding_box[3] // 2 self.append( Triangle( @@ -284,13 +258,9 @@ def __init__( self.append( Triangle( - self._bounding_box[0] - + self._bounding_box[2] - + self._arrow_gap, + self._bounding_box[0] + self._bounding_box[2] + self._arrow_gap, mid_point_y - arrow_height // 2, - self._bounding_box[0] - + self._bounding_box[2] - + self._arrow_gap, + self._bounding_box[0] + self._bounding_box[2] + self._arrow_gap, mid_point_y + arrow_height // 2, self._bounding_box[0] + self._bounding_box[2] @@ -301,44 +271,35 @@ def __init__( outline=arrow_outline, ) ) - else: # vertical orientation, add upper and lower arrows - if ( - (arrow_height is not None) - and (arrow_width is not None) - and (arrow_height > 0) - ): - mid_point_x = self._bounding_box[0] + self._bounding_box[2] // 2 - self.append( - Triangle( - mid_point_x - arrow_width // 2, - self._bounding_box[1] - self._arrow_gap, - mid_point_x + arrow_width // 2, - self._bounding_box[1] - self._arrow_gap, - mid_point_x, - self._bounding_box[1] - self._arrow_gap - arrow_height, - fill=arrow_color, - outline=arrow_outline, - ) + elif (arrow_height is not None) and (arrow_width is not None) and (arrow_height > 0): + mid_point_x = self._bounding_box[0] + self._bounding_box[2] // 2 + self.append( + Triangle( + mid_point_x - arrow_width // 2, + self._bounding_box[1] - self._arrow_gap, + mid_point_x + arrow_width // 2, + self._bounding_box[1] - self._arrow_gap, + mid_point_x, + self._bounding_box[1] - self._arrow_gap - arrow_height, + fill=arrow_color, + outline=arrow_outline, ) - self.append( - Triangle( - mid_point_x - arrow_width // 2, - self._bounding_box[1] - + self._bounding_box[3] - + self._arrow_gap, - mid_point_x + arrow_width // 2, - self._bounding_box[1] - + self._bounding_box[3] - + self._arrow_gap, - mid_point_x, - self._bounding_box[1] - + self._bounding_box[3] - + self._arrow_gap - + arrow_height, - fill=arrow_color, - outline=arrow_outline, - ) + ) + self.append( + Triangle( + mid_point_x - arrow_width // 2, + self._bounding_box[1] + self._bounding_box[3] + self._arrow_gap, + mid_point_x + arrow_width // 2, + self._bounding_box[1] + self._bounding_box[3] + self._arrow_gap, + mid_point_x, + self._bounding_box[1] + + self._bounding_box[3] + + self._arrow_gap + + arrow_height, + fill=arrow_color, + outline=arrow_outline, ) + ) # Draw function to update the current value def _update_value(self, new_value: int, animate: bool = True) -> None: @@ -370,9 +331,7 @@ def _update_value(self, new_value: int, animate: bool = True) -> None: palette = displayio.Palette(2) palette.make_transparent(0) palette[1] = self._color - animation_tilegrid = displayio.TileGrid( - animation_bitmap, pixel_shader=palette - ) + animation_tilegrid = displayio.TileGrid(animation_bitmap, pixel_shader=palette) # add bitmap to the animation_group self._animation_group.append(animation_tilegrid) @@ -452,9 +411,7 @@ def contains( # offsetting for self.x and self.y before calling the Control superclass function # ###### - touch_x = ( - touch_point[0] - self.x - ) # adjust touch position for the local position + touch_x = touch_point[0] - self.x # adjust touch position for the local position touch_y = touch_point[1] - self.y return super().contains((touch_x, touch_y, 0)) @@ -475,29 +432,22 @@ def selected(self, touch_point: Tuple[int, int, Optional[int]]) -> None: self.value = self.value - 1 elif ( - (t_b[0] + t_b[2] // 2) - <= (touch_point[0] - self.x) - <= (t_b[0] + t_b[2]) + (t_b[0] + t_b[2] // 2) <= (touch_point[0] - self.x) <= (t_b[0] + t_b[2]) ): # in right half of touch_boundary self.value = self.value + 1 - else: - if ( - t_b[1] <= (touch_point[1] - self.y) < (t_b[1] + t_b[3] // 2) - ): # in upper half of touch_boundary - self.value = self.value + 1 + elif ( + t_b[1] <= (touch_point[1] - self.y) < (t_b[1] + t_b[3] // 2) + ): # in upper half of touch_boundary + self.value = self.value + 1 - elif ( - (t_b[1] + t_b[3] // 2) - <= (touch_point[1] - self.y) - <= (t_b[1] + t_b[3]) - ): # in lower half of touch_boundary - self.value = self.value - 1 + elif ( + (t_b[1] + t_b[3] // 2) <= (touch_point[1] - self.y) <= (t_b[1] + t_b[3]) + ): # in lower half of touch_boundary + self.value = self.value - 1 self._pressed = True # update the state variable - self._last_pressed = ( - time.monotonic() - ) # value changed, so update cool_down timer + self._last_pressed = time.monotonic() # value changed, so update cool_down timer def released(self) -> None: """Response function when the Control is released. Resets the state variables @@ -525,9 +475,7 @@ def value( try: new_value = self.value_list.index(new_value) except ValueError: - print( - 'ValueError: Value "{}" not found in value_list.'.format(new_value) - ) + print(f'ValueError: Value "{new_value}" not found in value_list.') return None new_value = new_value % len(self.value_list) # Update the value @@ -590,9 +538,6 @@ def _draw_position( ) -# pylint: disable=invalid-name - - # _blit_constrained: Copies bitmaps with constraints to the dimensions def _blit_constrained( target: displayio.Bitmap, @@ -633,12 +578,7 @@ def _blit_constrained( if y2 > source.height: y2 = source.height - if ( - (x > target.width) - or (y > target.height) - or (x1 > source.width) - or (y1 > source.height) - ): + if (x > target.width) or (y > target.height) or (x1 > source.width) or (y1 > source.height): return target.blit(x, y, source, x1=x1, y1=y1, x2=x2, y2=y2) @@ -683,9 +623,7 @@ def _animate_bitmap( this_time = time.monotonic() target_position = ( start_position - + (end_position - start_position) - * (this_time - start_time) - / animation_time + + (end_position - start_position) * (this_time - start_time) / animation_time ) display.auto_refresh = False diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 2e5db2f..2e43821 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -21,19 +21,23 @@ https://github.com/adafruit/circuitpython/releases """ + import gc import time from math import pi -import bitmaptools -from displayio import TileGrid, Bitmap, Palette + import adafruit_imageload -from adafruit_displayio_layout.widgets.icon_widget import IconWidget -from adafruit_displayio_layout.widgets.easing import quadratic_easeout as easein +import bitmaptools +from displayio import Bitmap, Palette, TileGrid + from adafruit_displayio_layout.widgets.easing import quadratic_easein as easeout +from adafruit_displayio_layout.widgets.easing import quadratic_easeout as easein +from adafruit_displayio_layout.widgets.icon_widget import IconWidget try: from typing import Any, Optional, Tuple - from displayio import Display # pylint: disable=ungrouped-imports + + from busdisplay import BusDisplay except ImportError: pass @@ -43,7 +47,6 @@ class IconAnimated(IconWidget): - """ An animated touch enabled widget that holds an icon image loaded with OnDiskBitmap and a text label centered beneath it. Includes optional @@ -76,9 +79,6 @@ class IconAnimated(IconWidget): :type anchored_position: Tuple[int, int] """ - # pylint: disable=bad-super-call, too-many-instance-attributes, too-many-locals - # pylint: disable=too-many-arguments, unused-argument - display = None # The other Class variables are created in Class method `init_class`: # max_scale, bitmap_buffer, palette_buffer @@ -86,7 +86,7 @@ class IconAnimated(IconWidget): @classmethod def init_class( cls, - display: Optional[Display], + display: Optional[BusDisplay], max_scale: float = 1.5, max_icon_size: Tuple[int, int] = (80, 80), max_color_depth: int = 256, @@ -168,9 +168,8 @@ def __init__( if scale > self.__class__.max_scale: print( "Warning - IconAnimated: max_scale is constrained by value of " - "IconAnimated.max_scale set by IconAnimated.init_class(): {}".format( - self.__class__.max_scale - ) + "IconAnimated.max_scale set by " + f"IconAnimated.init_class(): {self.__class__.max_scale}" ) self._scale = max(0, min(scale, self.__class__.max_scale)) @@ -233,9 +232,7 @@ def zoom_animation(self, touch_point: Tuple[int, int, Optional[int]]) -> None: ) # blit the image into the center of the zoom_bitmap # place zoom_bitmap at same location as image - animation_tilegrid = TileGrid( - animation_bitmap, pixel_shader=animation_palette - ) + animation_tilegrid = TileGrid(animation_bitmap, pixel_shader=animation_palette) animation_tilegrid.x = -(animation_bitmap.width - _image.width) // 2 animation_tilegrid.y = -(animation_bitmap.height - _image.height) // 2 diff --git a/adafruit_displayio_layout/widgets/icon_widget.py b/adafruit_displayio_layout/widgets/icon_widget.py index 318d1c6..2a262cc 100644 --- a/adafruit_displayio_layout/widgets/icon_widget.py +++ b/adafruit_displayio_layout/widgets/icon_widget.py @@ -22,11 +22,11 @@ """ - -import terminalio -from displayio import TileGrid, OnDiskBitmap import adafruit_imageload +import terminalio from adafruit_display_text import bitmap_label +from displayio import OnDiskBitmap, TileGrid + from adafruit_displayio_layout.widgets.control import Control from adafruit_displayio_layout.widgets.widget import Widget @@ -41,7 +41,6 @@ class IconWidget(Widget, Control): - """ A touch enabled widget that holds an icon image loaded with adafruit_imageload and a text label centered beneath it. @@ -63,8 +62,6 @@ class IconWidget(Widget, Control): :type anchored_position: Tuple[int, int] """ - # pylint: disable=too-many-arguments - def __init__( self, label_text: str, @@ -72,7 +69,7 @@ def __init__( on_disk: bool = False, transparent_index: Optional[int] = None, label_background: Optional[int] = None, - **kwargs: Any + **kwargs: Any, ) -> None: super().__init__(**kwargs) @@ -120,9 +117,7 @@ def contains( :return: Boolean """ - touch_x = ( - touch_point[0] - self.x - ) # adjust touch position for the local position + touch_x = touch_point[0] - self.x # adjust touch position for the local position touch_y = touch_point[1] - self.y return super().contains((touch_x, touch_y, 0)) diff --git a/adafruit_displayio_layout/widgets/switch_round.py b/adafruit_displayio_layout/widgets/switch_round.py index e583b18..8ce0320 100644 --- a/adafruit_displayio_layout/widgets/switch_round.py +++ b/adafruit_displayio_layout/widgets/switch_round.py @@ -35,14 +35,16 @@ # import time + from adafruit_display_shapes.circle import Circle -from adafruit_display_shapes.roundrect import RoundRect from adafruit_display_shapes.rect import Rect -from adafruit_displayio_layout.widgets.widget import Widget +from adafruit_display_shapes.roundrect import RoundRect + from adafruit_displayio_layout.widgets.control import Control # modify the "easing" function that is imported to change the switch animation behaviour from adafruit_displayio_layout.widgets.easing import back_easeinout as easing +from adafruit_displayio_layout.widgets.widget import Widget try: from typing import Any, Optional, Tuple, Union @@ -55,7 +57,6 @@ class SwitchRound(Widget, Control): - """ .. note:: Jump directly to: @@ -419,9 +420,6 @@ class functions. The `Widget` class handles the overall sizing and positioning """ - # pylint: disable=too-many-instance-attributes, too-many-arguments, too-many-locals - # pylint: disable=too-many-branches, too-many-statements - def __init__( self, x: int = 0, @@ -469,7 +467,6 @@ def __init__( # initialize the Control superclass - # pylint: disable=bad-super-call super(Control, self).__init__() self._horizontal = horizontal @@ -698,9 +695,7 @@ def _draw_position(self, position: float) -> None: position = easing(position) # Get the position offset from the motion function - x_offset, y_offset, _ = self._get_offset_position( - position - ) # ignore angle_offset + x_offset, y_offset, _ = self._get_offset_position(position) # ignore angle_offset # Update the switch and text x- and y-positions self._switch_circle.x = self._switch_initial_x + x_offset @@ -711,9 +706,7 @@ def _draw_position(self, position: float) -> None: self._text_1.y = self._text_1_initial_y + y_offset # Set the color to the correct fade - self._switch_circle.fill = _color_fade( - self._fill_color_off, self._fill_color_on, position - ) + self._switch_circle.fill = _color_fade(self._fill_color_off, self._fill_color_on, position) self._switch_circle.outline = _color_fade( self._outline_color_off, self._outline_color_on, position ) @@ -774,9 +767,7 @@ def _animate_switch(self) -> None: elapsed_time = self._animation_time if self._value: - position = ( - 1 - (elapsed_time) / self._animation_time - ) # fraction from 0 to 1 + position = 1 - (elapsed_time) / self._animation_time # fraction from 0 to 1 else: # fraction from 0 to 1 position = (elapsed_time) / self._animation_time @@ -789,9 +780,7 @@ def _animate_switch(self) -> None: if (position >= 1) and not self._value: self._value = True break - if ( - position <= 0 - ) and self._value: # ensures that the final position is drawn + if (position <= 0) and self._value: # ensures that the final position is drawn self._value = False break @@ -807,9 +796,7 @@ def selected(self, touch_point: Tuple[int, int, Optional[int]]) -> None: self._animate_switch() # show the animation and switch the self._value - touch_x = ( - touch_point[0] - self.x - ) # adjust touch position for the local position + touch_x = touch_point[0] - self.x # adjust touch position for the local position touch_y = touch_point[1] - self.y # Call the parent's .selected function in case there is any work up there. @@ -827,9 +814,7 @@ def contains( :return: Boolean """ - touch_x = ( - touch_point[0] - self.x - ) # adjust touch position for the local position + touch_x = touch_point[0] - self.x # adjust touch position for the local position touch_y = touch_point[1] - self.y return super().contains((touch_x, touch_y, 0)) @@ -945,7 +930,5 @@ def _color_fade( faded_color = [0, 0, 0] for i in range(3): - faded_color[i] = start_color[i] - int( - (start_color[i] - end_color[i]) * fraction - ) + faded_color[i] = start_color[i] - int((start_color[i] - end_color[i]) * fraction) return tuple(faded_color) diff --git a/adafruit_displayio_layout/widgets/widget.py b/adafruit_displayio_layout/widgets/widget.py index 7a376f1..2e6bd8d 100644 --- a/adafruit_displayio_layout/widgets/widget.py +++ b/adafruit_displayio_layout/widgets/widget.py @@ -33,8 +33,6 @@ __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git" -# pylint: disable=too-many-arguments - class Widget(displayio.Group): """ diff --git a/docs/api.rst b/docs/api.rst index a707e30..0cddc93 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,6 +4,9 @@ .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. use this format as the module name: "adafruit_foo.foo" +API Reference +############# + .. automodule:: adafruit_displayio_layout.layouts.grid_layout :members: :private-members: diff --git a/docs/conf.py b/docs/conf.py index a314186..a0e4431 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- - # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: MIT +import datetime import os import sys -import datetime sys.path.insert(0, os.path.abspath("..")) @@ -55,9 +53,7 @@ creation_year = "2021" current_year = str(datetime.datetime.now().year) year_duration = ( - current_year - if current_year == creation_year - else creation_year + " - " + current_year + current_year if current_year == creation_year else creation_year + " - " + current_year ) copyright = year_duration + " Tim Cocks" author = "Tim Cocks" diff --git a/examples/displayio_layout_cartesian_advanced_test.py b/examples/displayio_layout_cartesian_advanced_test.py index e10a765..3acda2e 100644 --- a/examples/displayio_layout_cartesian_advanced_test.py +++ b/examples/displayio_layout_cartesian_advanced_test.py @@ -10,6 +10,7 @@ import board import displayio import terminalio + from adafruit_displayio_layout.widgets.cartesian import Cartesian # Fonts used for the Dial tick labels diff --git a/examples/displayio_layout_cartesian_lineplot.py b/examples/displayio_layout_cartesian_lineplot.py index 14683a0..54ac442 100644 --- a/examples/displayio_layout_cartesian_lineplot.py +++ b/examples/displayio_layout_cartesian_lineplot.py @@ -7,8 +7,10 @@ """ import time + import board import displayio + from adafruit_displayio_layout.widgets.cartesian import Cartesian # create the display on the PyPortal or Clue or PyBadge(for example) diff --git a/examples/displayio_layout_cartesian_simpletest.py b/examples/displayio_layout_cartesian_simpletest.py index e859380..ba1353c 100644 --- a/examples/displayio_layout_cartesian_simpletest.py +++ b/examples/displayio_layout_cartesian_simpletest.py @@ -7,9 +7,11 @@ """ import time + import board import displayio import terminalio + from adafruit_displayio_layout.widgets.cartesian import Cartesian # Fonts used for the Dial tick labels diff --git a/examples/displayio_layout_flip_input_simpletest.py b/examples/displayio_layout_flip_input_simpletest.py index c51c00d..c6c3ce0 100755 --- a/examples/displayio_layout_flip_input_simpletest.py +++ b/examples/displayio_layout_flip_input_simpletest.py @@ -6,13 +6,13 @@ This is a basic demonstration of a FlipInput widget. """ -# pylint: disable=invalid-name - import time + +import adafruit_touchscreen import board import displayio -import adafruit_touchscreen from adafruit_bitmap_font import bitmap_font + from adafruit_displayio_layout.widgets.flip_input import FlipInput display = board.DISPLAY # create the display on the PyPortal, @@ -62,7 +62,7 @@ anchor_point=[0.0, 0.0], anchored_position=[220, 40], color=0xFF2222, # reddish orange color - value_list=["{0:02d}".format(x) for x in range(1, 31 + 1)], + value_list=[f"{x:02d}" for x in range(1, 31 + 1)], # use a list of strings from 01 through 31 # use the {0:02d} format string to always use two digits (e.g. '03') font_scale=5, @@ -75,7 +75,7 @@ anchor_point=[0.5, 1.0], anchored_position=[320 // 2, 240 - 10], color=0xFF2222, # reddish orange color - value_list=["{}".format(x) for x in range(1985, 2022, 1)], + value_list=[f"{x}" for x in range(1985, 2022, 1)], # use a list with values of stringsfrom 1985 to 2022 font=my_font, horizontal=True, # use horizontal arrows diff --git a/examples/displayio_layout_grid_layout_get_cell_test.py b/examples/displayio_layout_grid_layout_get_cell_test.py index 9e6d674..06ccfd0 100644 --- a/examples/displayio_layout_grid_layout_get_cell_test.py +++ b/examples/displayio_layout_grid_layout_get_cell_test.py @@ -5,10 +5,12 @@ Make green and purple rectangles and then update the color and text values of the labels using the get_cell() function. """ + import board import displayio import terminalio from adafruit_display_text import label + from adafruit_displayio_layout.layouts.grid_layout import GridLayout # use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.) @@ -31,15 +33,11 @@ _labels = [] _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077) ) layout.add_content(_labels[0], grid_position=(0, 0), cell_size=(1, 1)) _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700) ) layout.add_content(_labels[1], grid_position=(1, 0), cell_size=(1, 1)) _labels.append(label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello")) diff --git a/examples/displayio_layout_gridlayout_dividers.py b/examples/displayio_layout_gridlayout_dividers.py index d7cefab..34e47b9 100644 --- a/examples/displayio_layout_gridlayout_dividers.py +++ b/examples/displayio_layout_gridlayout_dividers.py @@ -4,10 +4,12 @@ """ Illustrate how to use divider lines with GridLayout """ + import board import displayio import terminalio from adafruit_display_text import label + from adafruit_displayio_layout.layouts.grid_layout import GridLayout # use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.) @@ -31,15 +33,11 @@ _labels = [] _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077) ) layout.add_content(_labels[0], grid_position=(0, 0), cell_size=(1, 1)) _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700) ) layout.add_content(_labels[1], grid_position=(1, 0), cell_size=(1, 1)) _labels.append(label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello")) diff --git a/examples/displayio_layout_gridlayout_pygame_display_simpletest.py b/examples/displayio_layout_gridlayout_pygame_display_simpletest.py index 15fa6d9..f0a5623 100644 --- a/examples/displayio_layout_gridlayout_pygame_display_simpletest.py +++ b/examples/displayio_layout_gridlayout_pygame_display_simpletest.py @@ -7,12 +7,12 @@ Requires: https://github.com/FoamyGuy/Blinka_Displayio_PyGameDisplay """ + import displayio import terminalio from adafruit_display_text import label from blinka_displayio_pygamedisplay import PyGameDisplay - # Make the display context. Change size if you want from adafruit_displayio_layout.layouts.grid_layout import GridLayout @@ -31,15 +31,11 @@ _labels = [] _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077) ) layout.add_content(_labels[0], grid_position=(0, 0), cell_size=(1, 1)) _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700) ) layout.add_content(_labels[1], grid_position=(1, 0), cell_size=(1, 1)) _labels.append(label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello")) diff --git a/examples/displayio_layout_gridlayout_simpletest.py b/examples/displayio_layout_gridlayout_simpletest.py index 0816dd7..2d0b3ad 100644 --- a/examples/displayio_layout_gridlayout_simpletest.py +++ b/examples/displayio_layout_gridlayout_simpletest.py @@ -5,10 +5,12 @@ Make green and purple rectangles and a "Hello World" label. """ + import board import displayio import terminalio from adafruit_display_text import label + from adafruit_displayio_layout.layouts.grid_layout import GridLayout # use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.) @@ -31,15 +33,11 @@ _labels = [] _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077) ) layout.add_content(_labels[0], grid_position=(0, 0), cell_size=(1, 1)) _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700) ) layout.add_content(_labels[1], grid_position=(1, 0), cell_size=(1, 1)) _labels.append(label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello")) diff --git a/examples/displayio_layout_icon_animated_simpletest.py b/examples/displayio_layout_icon_animated_simpletest.py index c8cb37a..3ec9851 100644 --- a/examples/displayio_layout_icon_animated_simpletest.py +++ b/examples/displayio_layout_icon_animated_simpletest.py @@ -4,10 +4,13 @@ """ Creates two animated icons with touch response: zoom and shrink animations. """ + import time + +import adafruit_touchscreen import board import displayio -import adafruit_touchscreen + from adafruit_displayio_layout.widgets.icon_animated import IconAnimated display = board.DISPLAY @@ -22,9 +25,7 @@ ) -IconAnimated.init_class( - display, max_scale=1.5, max_icon_size=(48, 48), max_color_depth=255 -) +IconAnimated.init_class(display, max_scale=1.5, max_icon_size=(48, 48), max_color_depth=255) icon_zoom = IconAnimated( "Zoom", diff --git a/examples/displayio_layout_linearlayout_simpletest.py b/examples/displayio_layout_linearlayout_simpletest.py index 4090561..1925330 100644 --- a/examples/displayio_layout_linearlayout_simpletest.py +++ b/examples/displayio_layout_linearlayout_simpletest.py @@ -5,11 +5,13 @@ Illustrates usage of LinearLayout to display a text label to the right of an icon. """ + import adafruit_imageload import board import displayio import terminalio from adafruit_display_text import label + from adafruit_displayio_layout.layouts.linear_layout import LinearLayout # use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.) @@ -21,9 +23,7 @@ main_group = displayio.Group() display.root_group = main_group -layout = LinearLayout( - x=10, y=10, padding=4, orientation=LinearLayout.HORIZONTAL_ORIENTATION -) +layout = LinearLayout(x=10, y=10, padding=4, orientation=LinearLayout.HORIZONTAL_ORIENTATION) lbl = label.Label(terminalio.FONT, scale=4, x=0, y=0, text="Hello") diff --git a/examples/displayio_layout_page_layout_advancedtest.py b/examples/displayio_layout_page_layout_advancedtest.py index 9a6bde8..7dbdca7 100644 --- a/examples/displayio_layout_page_layout_advancedtest.py +++ b/examples/displayio_layout_page_layout_advancedtest.py @@ -4,14 +4,17 @@ """ Make a PageLayout and illustrate all of it's features """ + import time -import displayio + import board +import displayio import terminalio -from adafruit_display_text.bitmap_label import Label -from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.triangle import Triangle +from adafruit_display_text.bitmap_label import Label + from adafruit_displayio_layout.layouts.page_layout import PageLayout # built-in display @@ -77,22 +80,22 @@ # change page with function by name test_page_layout.show_page(page_name="page_3") -print("showing page index:{}".format(test_page_layout.showing_page_index)) +print(f"showing page index:{test_page_layout.showing_page_index}") time.sleep(1) # change page with function by index test_page_layout.show_page(page_index=0) -print("showing page name: {}".format(test_page_layout.showing_page_name)) +print(f"showing page name: {test_page_layout.showing_page_name}") time.sleep(1) # change page by updating the page name property test_page_layout.showing_page_name = "page_3" -print("showing page index: {}".format(test_page_layout.showing_page_index)) +print(f"showing page index: {test_page_layout.showing_page_index}") time.sleep(1) # change page by updating the page index property test_page_layout.showing_page_index = 1 -print("showing page name: {}".format(test_page_layout.showing_page_name)) +print(f"showing page name: {test_page_layout.showing_page_name}") time.sleep(5) another_text = Label( diff --git a/examples/displayio_layout_page_layout_simpletest.py b/examples/displayio_layout_page_layout_simpletest.py index b11c02c..74e3120 100644 --- a/examples/displayio_layout_page_layout_simpletest.py +++ b/examples/displayio_layout_page_layout_simpletest.py @@ -4,13 +4,16 @@ """ Make a PageLayout with two pages and change between them. """ + import time -import displayio + import board +import displayio import terminalio -from adafruit_display_text.bitmap_label import Label -from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.rect import Rect +from adafruit_display_text.bitmap_label import Label + from adafruit_displayio_layout.layouts.page_layout import PageLayout # built-in display diff --git a/examples/displayio_layout_pygame_display_switch_round.py b/examples/displayio_layout_pygame_display_switch_round.py index c21111b..c85f241 100644 --- a/examples/displayio_layout_pygame_display_switch_round.py +++ b/examples/displayio_layout_pygame_display_switch_round.py @@ -7,11 +7,12 @@ Requires: https://github.com/FoamyGuy/Blinka_Displayio_PyGameDisplay """ + import displayio import pygame from blinka_displayio_pygamedisplay import PyGameDisplay -from adafruit_displayio_layout.widgets.switch_round import SwitchRound as Switch +from adafruit_displayio_layout.widgets.switch_round import SwitchRound as Switch # Make the display context. Change size if you want display = PyGameDisplay(width=320, height=240) diff --git a/examples/displayio_layout_simpletest.py b/examples/displayio_layout_simpletest.py index 16b3bb4..2b79736 100644 --- a/examples/displayio_layout_simpletest.py +++ b/examples/displayio_layout_simpletest.py @@ -7,10 +7,12 @@ Make green and purple rectangles and a "Hello World" label. """ + import board import displayio import terminalio from adafruit_display_text import label + from adafruit_displayio_layout.layouts.grid_layout import GridLayout # use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.) @@ -33,15 +35,11 @@ _labels = [] _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello", background_color=0x770077) ) layout.add_content(_labels[0], grid_position=(0, 0), cell_size=(1, 1)) _labels.append( - label.Label( - terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700 - ) + label.Label(terminalio.FONT, scale=2, x=0, y=0, text="World", background_color=0x007700) ) layout.add_content(_labels[1], grid_position=(1, 0), cell_size=(1, 1)) _labels.append(label.Label(terminalio.FONT, scale=2, x=0, y=0, text="Hello")) diff --git a/examples/displayio_layout_switch_multiple.py b/examples/displayio_layout_switch_multiple.py index 6cb1bab..5f8a2ce 100755 --- a/examples/displayio_layout_switch_multiple.py +++ b/examples/displayio_layout_switch_multiple.py @@ -6,9 +6,11 @@ """ import time + +import adafruit_touchscreen import board import displayio -import adafruit_touchscreen + from adafruit_displayio_layout.widgets.switch_round import SwitchRound as Switch display = board.DISPLAY diff --git a/examples/displayio_layout_switch_simpletest.py b/examples/displayio_layout_switch_simpletest.py index a9cfbc8..432c1e0 100644 --- a/examples/displayio_layout_switch_simpletest.py +++ b/examples/displayio_layout_switch_simpletest.py @@ -6,9 +6,11 @@ """ import time + +import adafruit_touchscreen import board import displayio -import adafruit_touchscreen + from adafruit_displayio_layout.widgets.switch_round import SwitchRound as Switch display = board.DISPLAY diff --git a/examples/displayio_layout_tab_layout_simpletest.py b/examples/displayio_layout_tab_layout_simpletest.py index 188cd75..c8c73b4 100644 --- a/examples/displayio_layout_tab_layout_simpletest.py +++ b/examples/displayio_layout_tab_layout_simpletest.py @@ -4,14 +4,17 @@ """ Make a TabLayout and illustrate the most basic features and usage. """ + import time -import displayio + import board +import displayio import terminalio -from adafruit_display_text.bitmap_label import Label -from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.triangle import Triangle +from adafruit_display_text.bitmap_label import Label + from adafruit_displayio_layout.layouts.tab_layout import TabLayout CHANGE_DELAY = 1.0 # Seconds to wait before auto-advancing to the next tab @@ -108,22 +111,22 @@ # change page with function by name test_page_layout.show_page(page_name="Thr") -print("showing page index:{}".format(test_page_layout.showing_page_index)) +print(f"showing page index:{test_page_layout.showing_page_index}") time.sleep(1) # change page with function by index test_page_layout.show_page(page_index=0) -print("showing page name: {}".format(test_page_layout.showing_page_name)) +print(f"showing page name: {test_page_layout.showing_page_name}") time.sleep(1) # change page by updating the page name property test_page_layout.showing_page_name = "Thr" -print("showing page index: {}".format(test_page_layout.showing_page_index)) +print(f"showing page index: {test_page_layout.showing_page_index}") time.sleep(1) # change page by updating the page index property test_page_layout.showing_page_index = 1 -print("showing page name: {}".format(test_page_layout.showing_page_name)) +print(f"showing page name: {test_page_layout.showing_page_name}") time.sleep(5) another_text = Label( diff --git a/examples/displayio_layout_tab_layout_touchtest.py b/examples/displayio_layout_tab_layout_touchtest.py index e8fe6ee..a58db70 100644 --- a/examples/displayio_layout_tab_layout_touchtest.py +++ b/examples/displayio_layout_tab_layout_touchtest.py @@ -4,14 +4,16 @@ """ Make a TabLayout change tabs with the touchscreen """ -import displayio + +import adafruit_touchscreen import board +import displayio import terminalio -import adafruit_touchscreen -from adafruit_display_text.bitmap_label import Label -from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.triangle import Triangle +from adafruit_display_text.bitmap_label import Label + from adafruit_displayio_layout.layouts.tab_layout import TabLayout # built-in display diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py index 041bbcf..1268b53 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_rtc.py @@ -6,16 +6,18 @@ """ import time -import displayio + +import adafruit_tmp117 import board +import displayio import terminalio -import adafruit_tmp117 -from adafruit_ds3231 import DS3231 -from adafruit_display_text.bitmap_label import Label -from adafruit_display_shapes.rect import Rect +from adafruit_bitmap_font import bitmap_font from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.rect import Rect from adafruit_display_shapes.triangle import Triangle -from adafruit_bitmap_font import bitmap_font +from adafruit_display_text.bitmap_label import Label +from adafruit_ds3231 import DS3231 + from adafruit_displayio_layout.layouts.tab_layout import TabLayout # +-------------------------------------------------------+ @@ -89,13 +91,9 @@ def write(self, s, value): # key: {}".format(s, n)) self.g_vars[n] = value else: - raise KeyError( - "variable '{:" ">20s}' not found in self.gVars_rDict".format(s) - ) + raise KeyError("variable '{:" ">20s}' not found in self.gVars_rDict".format(s)) else: - raise TypeError( - "myVars.write(): param s expected str, {} received".format(type(s)) - ) + raise TypeError(f"myVars.write(): param s expected str, {type(s)} received") def read(self, s): RetVal = None @@ -135,8 +133,7 @@ def clean(self): def list(self): for i in range(0, len(self.g_vars) - 1): print( - "self.g_vars['{:" - ">20s}'] = {}".format( + "self.g_vars['{:" ">20s}'] = {}".format( self.gVarsDict[i], self.g_vars[i] if i in self.g_vars else "None" ) ) @@ -358,22 +355,22 @@ def list(self): # change page with function by name test_page_layout.show_page(page_name=pages[2]) -print("showing page index:{}".format(test_page_layout.showing_page_index)) +print(f"showing page index:{test_page_layout.showing_page_index}") time.sleep(1) # change page with function by index test_page_layout.show_page(page_index=0) -print("showing page name: {}".format(test_page_layout.showing_page_name)) +print(f"showing page name: {test_page_layout.showing_page_name}") time.sleep(1) # change page by updating the page name property test_page_layout.showing_page_name = pages[2] -print("showing page index: {}".format(test_page_layout.showing_page_index)) +print(f"showing page index: {test_page_layout.showing_page_index}") time.sleep(1) # change page by updating the page index property test_page_layout.showing_page_index = 1 -print("showing page name: {}".format(test_page_layout.showing_page_name)) +print(f"showing page name: {test_page_layout.showing_page_name}") time.sleep(5) """ @@ -471,12 +468,8 @@ def get_temp(): temp = myVars.read("temp_sensor").temperature if myVars.read("temp_in_fahrenheit"): temp = (temp * 1.8) + 32 - t = "{:5.2f} ".format(temp) + myVars.read("t1") - if ( - myVars.read("my_debug") - and temp is not None - and not myVars.read("temp_in_REPL") - ): + t = f"{temp:5.2f} " + myVars.read("t1") + if myVars.read("my_debug") and temp is not None and not myVars.read("temp_in_REPL"): myVars.write("temp_in_REPL", True) print("get_temp(): {} {}".format(myVars.read("t0"), t)) if showing_page_idx == 3: # show temperature on most right Tab page @@ -485,7 +478,7 @@ def get_temp(): "old_temp" ): # Only update if there is a change in temperature myVars.write("old_temp", temp) - t = "{:5.2f} ".format(temp) + myVars.read("t1") + t = f"{temp:5.2f} " + myVars.read("t1") pge4_lbl.text = "" pge4_lbl2.text = myVars.read("t0") pge4_lbl3.text = t @@ -500,20 +493,13 @@ def get_temp(): print("Temperature sensor has disconnected") t = "" myVars.write("temp_sensor", None) - pge4_lbl.text = myVars.read( - "pge4_lbl_dflt" - ) # clean the line (eventually: t2) + pge4_lbl.text = myVars.read("pge4_lbl_dflt") # clean the line (eventually: t2) pge4_lbl2.text = "" pge4_lbl3.text = "" return RetVal -""" - Function called by get_dt() - Created to repair pylint error R0912: Too many branches (13/12) -""" - yy = 0 mo = 1 dd = 2 @@ -562,14 +548,14 @@ def handle_dt(dt): if myVars.read("c_secs") != myVars.read("o_secs"): myVars.write("o_secs", myVars.read("c_secs")) - sDT3 = s + "{} {}".format(sDT, sDT2) + sDT3 = s + f"{sDT} {sDT2}" print(sDT3) pge3_lbl3.text = sDT2 if myVars.read("my_debug"): - print("pge3_lbl.text = {}".format(pge3_lbl.text)) - print("pge3_lbl2.text = {}".format(pge3_lbl2.text)) - print("pge3_lbl3.text = {}".format(pge3_lbl3.text)) + print(f"pge3_lbl.text = {pge3_lbl.text}") + print(f"pge3_lbl2.text = {pge3_lbl2.text}") + print(f"pge3_lbl3.text = {pge3_lbl3.text}") RetVal = True # Return from here with a False but don't set the pge3_lbl to default. @@ -627,7 +613,7 @@ def main(): cnt = 0 while True: try: - print("Loop nr: {:03d}".format(cnt)) + print(f"Loop nr: {cnt:03d}") # print("main(): type(rtc) object = ", type(myVars.read("rtc"))) if myVars.read("rtc") is not None: get_dt() diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py index 6ec1cb1..81cd23d 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py @@ -9,26 +9,28 @@ However, when the flag 'use_ntp' is set, the DS3231 will not be used instead the NTP class from adafruit_ntp.py will be used. """ + import time + +import adafruit_tmp117 +import adafruit_touchscreen import board import busio import displayio +import neopixel import terminalio -import adafruit_tmp117 +from adafruit_bitmap_font import bitmap_font +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.triangle import Triangle +from adafruit_display_text.bitmap_label import Label from adafruit_ds3231 import DS3231 -from digitalio import DigitalInOut -import neopixel -import adafruit_touchscreen from adafruit_esp32spi import adafruit_esp32spi from adafruit_ntp import NTP from adafruit_pyportal import PyPortal -from adafruit_display_text.bitmap_label import Label -from adafruit_display_shapes.rect import Rect -from adafruit_display_shapes.circle import Circle -from adafruit_display_shapes.triangle import Triangle -from adafruit_bitmap_font import bitmap_font -from adafruit_displayio_layout.layouts.tab_layout import TabLayout +from digitalio import DigitalInOut +from adafruit_displayio_layout.layouts.tab_layout import TabLayout # +-------------------------------------------------------+ # | Definition for variables in the past defined as global| @@ -115,13 +117,9 @@ def write(self, s, value): # key: {}".format(s, n)) self.g_vars[n] = value else: - raise KeyError( - "variable '{:" ">20s}' not found in self.gVars_rDict".format(s) - ) + raise KeyError("variable '{:" ">20s}' not found in self.gVars_rDict".format(s)) else: - raise TypeError( - "myVars.write(): param s expected str, {} received".format(type(s)) - ) + raise TypeError(f"myVars.write(): param s expected str, {type(s)} received") def read(self, s): RetVal = None @@ -168,8 +166,7 @@ def clean(self): def list(self): for i in range(0, len(self.g_vars) - 1): print( - "self.g_vars['{:" - ">20s}'] = {}".format( + "self.g_vars['{:" ">20s}'] = {}".format( self.gVarsDict[i], self.g_vars[i] if i in self.g_vars else "None" ) ) @@ -337,10 +334,7 @@ def list(self): print("Please wait...") if myVars.read("my_debug"): print("My IP address is", esp.pretty_ip(esp.ip_address)) - print( - "IP lookup adafruit.com: %s" - % esp.pretty_ip(esp.get_host_by_name("adafruit.com")) - ) + print("IP lookup adafruit.com: %s" % esp.pretty_ip(esp.get_host_by_name("adafruit.com"))) print("Ping google.com: %d ms" % esp.ping("google.com")) @@ -368,7 +362,7 @@ def refresh_from_NTP(): # (defined in secrets.h) ntp_current_time = time.time() if myVars.read("my_debug"): - print("Seconds since Jan 1, 1970: {} seconds".format(ntp_current_time)) + print(f"Seconds since Jan 1, 1970: {ntp_current_time} seconds") # Convert the current time in seconds since Jan 1, 1970 to a struct_time myVars.write("default_dt", time.localtime(ntp_current_time)) @@ -761,33 +755,22 @@ def get_temp(): print("Temperature sensor has disconnected") t = "" myVars.write("temp_sensor", None) - pge4_lbl.text = myVars.read( - "pge4_lbl_dflt" - ) # clean the line (eventually: t2) + pge4_lbl.text = myVars.read("pge4_lbl_dflt") # clean the line (eventually: t2) pge4_lbl2.text = "Sensor disconnected." pge4_lbl3.text = "Check wiring." return RetVal -# Moved these six definitions outside handle_dt() -# to correct pylint error 'too many variables' dt_ridxs = {"yy": 0, "mo": 1, "dd": 2, "hh": 3, "mm": 4, "ss": 5} # print("dict dt_ridxs =", dt_ridxs.keys()) -""" Function called by get_dt() - Created to repair pylint error R0912: Too many branches (13/12)""" - - def handle_dt(dt): my_debug = myVars.read("my_debug") RetVal = False s = "Date/time: " sYY = str(dt[dt_ridxs["yy"]]) # was: str(dt[yy]) - # print("dt_ridxs["mo"] = ", dt_ridxs["mo"]) - # modified mo because plynt error R0914 'Too many local variables' - # mo = dt_ridxs["mo"] dd = dt_ridxs["dd"] hh = dt_ridxs["hh"] mm = dt_ridxs["mm"] @@ -831,14 +814,14 @@ def handle_dt(dt): if myVars.read("c_secs") != myVars.read("o_secs"): myVars.write("o_secs", myVars.read("c_secs")) - sDT3 = s + "{} {}".format(sDT, sDT2) + sDT3 = s + f"{sDT} {sDT2}" print(sDT3) pge3_lbl3.text = sDT2 if my_debug: - print("pge3_lbl.text = {}".format(pge3_lbl.text)) - print("pge3_lbl2.text = {}".format(pge3_lbl2.text)) - print("pge3_lbl3.text = {}".format(pge3_lbl3.text)) + print(f"pge3_lbl.text = {pge3_lbl.text}") + print(f"pge3_lbl2.text = {pge3_lbl2.text}") + print(f"pge3_lbl3.text = {pge3_lbl3.text}") RetVal = True # Return from here with a False but don't set the pge3_lbl to default. @@ -898,11 +881,6 @@ def hms_to_cnt(): return (dt.tm_hour * 3600) + (dt.tm_min * 60) + dt.tm_sec -""" Created this function to correct pylint errors: - 'Too many branches' R0912 and - 'Too many statements' R0915""" - - def ck_next_NTP_sync(): s_cnt = myVars.read("s_cnt") c_cnt = hms_to_cnt() # set current count (seconds) @@ -917,9 +895,7 @@ def ck_next_NTP_sync(): myVars.write("s_cnt", hms_to_cnt()) # --- five minutes count down calculations #1 --- if my_debug: - print( - TAG + "five_min = {}, s_cnt = {}, c_cnt = {}".format(five_min, s_cnt, c_cnt) - ) + print(TAG + f"five_min = {five_min}, s_cnt = {s_cnt}, c_cnt = {c_cnt}") print(TAG + "c_elapsed = ", c_elapsed) # --- five minutes count down calculations #2 --- @@ -928,7 +904,7 @@ def ck_next_NTP_sync(): myVars.write("five_min_cnt", five_min) # remember count mm2 = five_min // 60 ss2 = five_min - (mm2 * 60) - t2 = "{:02d}:{:02d}".format(mm2, ss2) + t2 = f"{mm2:02d}:{ss2:02d}" t0 = t1 + t2 + t3 print(t0) pge3_lbl4.text = t0 @@ -973,7 +949,7 @@ def main(): if otp and ntp_refresh: refresh_from_NTP() # first re-synchronize internal clock from NTP server if get_dt(): - print("Loop nr: {:03d}".format(cnt)) + print(f"Loop nr: {cnt:03d}") else: connect_rtc() if myVars.read("temp_sensor") is not None: diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..5a5dbf0 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,101 @@ +# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +target-version = "py38" +line-length = 100 + +[lint] +preview = true +select = ["I", "PL", "UP"] + +extend-select = [ + "D419", # empty-docstring + "E501", # line-too-long + "W291", # trailing-whitespace + "PLC0414", # useless-import-alias + "PLC2401", # non-ascii-name + "PLC2801", # unnecessary-dunder-call + "PLC3002", # unnecessary-direct-lambda-call + "E999", # syntax-error + "PLE0101", # return-in-init + "F706", # return-outside-function + "F704", # yield-outside-function + "PLE0116", # continue-in-finally + "PLE0117", # nonlocal-without-binding + "PLE0241", # duplicate-bases + "PLE0302", # unexpected-special-method-signature + "PLE0604", # invalid-all-object + "PLE0605", # invalid-all-format + "PLE0643", # potential-index-error + "PLE0704", # misplaced-bare-raise + "PLE1141", # dict-iter-missing-items + "PLE1142", # await-outside-async + "PLE1205", # logging-too-many-args + "PLE1206", # logging-too-few-args + "PLE1307", # bad-string-format-type + "PLE1310", # bad-str-strip-call + "PLE1507", # invalid-envvar-value + "PLE2502", # bidirectional-unicode + "PLE2510", # invalid-character-backspace + "PLE2512", # invalid-character-sub + "PLE2513", # invalid-character-esc + "PLE2514", # invalid-character-nul + "PLE2515", # invalid-character-zero-width-space + "PLR0124", # comparison-with-itself + "PLR0202", # no-classmethod-decorator + "PLR0203", # no-staticmethod-decorator + "UP004", # useless-object-inheritance + "PLR0206", # property-with-parameters + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0916", # too-many-boolean-expressions + "PLR1702", # too-many-nested-blocks + "PLR1704", # redefined-argument-from-local + "PLR1711", # useless-return + "C416", # unnecessary-comprehension + "PLR1733", # unnecessary-dict-index-lookup + "PLR1736", # unnecessary-list-index-lookup + + # ruff reports this rule is unstable + #"PLR6301", # no-self-use + + "PLW0108", # unnecessary-lambda + "PLW0120", # useless-else-on-loop + "PLW0127", # self-assigning-variable + "PLW0129", # assert-on-string-literal + "B033", # duplicate-value + "PLW0131", # named-expr-without-context + "PLW0245", # super-without-brackets + "PLW0406", # import-self + "PLW0602", # global-variable-not-assigned + "PLW0603", # global-statement + "PLW0604", # global-at-module-level + + # fails on the try: import typing used by libraries + #"F401", # unused-import + + "F841", # unused-variable + "E722", # bare-except + "PLW0711", # binary-op-exception + "PLW1501", # bad-open-mode + "PLW1508", # invalid-envvar-default + "PLW1509", # subprocess-popen-preexec-fn + "PLW2101", # useless-with-lock + "PLW3301", # nested-min-max +] + +ignore = [ + "PLR2004", # magic-value-comparison + "UP030", # format literals + "PLW1514", # unspecified-encoding + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLR0914", # too-many-locals + "PLR0915", # too-many-statements + "PLR0917", # too-many-positional-arguments + +] + +[format] +line-ending = "lf" From 7a6bc24462e4e72c3b0942a89ac6f3e239bee573 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 24 Feb 2025 18:24:19 -0600 Subject: [PATCH 126/132] use plus between f-strings --- adafruit_displayio_layout/widgets/cartesian.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/adafruit_displayio_layout/widgets/cartesian.py b/adafruit_displayio_layout/widgets/cartesian.py index 21bbdc8..50ca8a3 100644 --- a/adafruit_displayio_layout/widgets/cartesian.py +++ b/adafruit_displayio_layout/widgets/cartesian.py @@ -479,15 +479,14 @@ def _add_point(self, x: int, y: int) -> None: print("") print( f"xy: ({x: >4}, {y: >4}) " - f"_xrange: ({self._xrange[0]: >4}, {self._xrange[1]: >4}) " - f"_yrange: ({self._yrange[0]: >4}, {self._yrange[1]: >4}) " + + f"_xrange: ({self._xrange[0]: >4}, {self._xrange[1]: >4}) " + + f"_yrange: ({self._yrange[0]: >4}, {self._yrange[1]: >4}) " "" ) print( f"local_*: ({local_x: >4}, {local_y: >4}) " - f" width: ({0: >4}, {self.width: >4}) " - f" height: ({0: >4}, {self.height: >4}) " - "" + + f" width: ({0: >4}, {self.width: >4}) " + + f" height: ({0: >4}, {self.height: >4}) " ) if self._check_xy_in_range(x, y): if self._check_local_xy_in_range(local_x, local_y): From 2f031fc9e3eb2e56f7d38d969c76e689ddd97fb1 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Thu, 27 Feb 2025 15:38:32 -0800 Subject: [PATCH 127/132] Remove secrets usage --- .../displayio_layout_hotplug_temp_sensor.py | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py index 81cd23d..7c2a0dd 100644 --- a/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py +++ b/examples/hotplug_sensor_examples/displayio_layout_hotplug_temp_sensor.py @@ -11,6 +11,7 @@ """ import time +from os import getenv import adafruit_tmp117 import adafruit_touchscreen @@ -275,7 +276,7 @@ def list(self): ) else: print("\nTabLayout test with I2C Temperature sensor and I2C Realtime clock") -print("Add your WiFi SSID, WiFi password and Timezone in file: secrets.h\n") +print("Add your WiFi SSID, WiFi password and Timezone in file: settings.toml\n") if myVars.read("my_debug"): while not i2c.try_lock(): @@ -303,13 +304,9 @@ def list(self): # NOTE: there is also the board.SD_CARD_DETECT pin (33)(but I don't know yet how to interface it) #### -# you'll need to pass in an io username and key -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") if myVars.read("my_debug"): if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: @@ -320,13 +317,13 @@ def list(self): for ap in esp.scan_networks(): print("\t%s\t\tRSSI: %d" % (str(ap["ssid"], "utf-8"), ap["rssi"])) -# Get our username, key and desired timezone -location = secrets.get("timezone", None) +# Get our desired timezone +location = getenv("timezone", None) print("\nConnecting to AP...") while not esp.is_connected: try: - esp.connect_AP(secrets["ssid"], secrets["password"]) + esp.connect_AP(ssid, password) except RuntimeError as e: print("could not connect to AP, retrying: ", e) continue @@ -359,7 +356,7 @@ def refresh_from_NTP(): myVars.write("online_time_present", True) myVars.write("ntp_refresh", False) # Get the current time in seconds since Jan 1, 1970 and correct it for local timezone - # (defined in secrets.h) + # (defined in settings.toml) ntp_current_time = time.time() if myVars.read("my_debug"): print(f"Seconds since Jan 1, 1970: {ntp_current_time} seconds") @@ -377,9 +374,9 @@ def refresh_from_NTP(): # Initialize the NTP object ntp = NTP(esp) - location = secrets.get("timezone", location) + location = getenv("timezone", location) if myVars.read("my_debug"): - print("location (from secrets.h) = ", location) + print(f"location (from settings.toml) = {location}") if location == "Europe/Lisbon": if myVars.read("my_debug"): print("Using timezone Europe/Lisbon") From 746b1886b58dd4ef10ac369a7f59c4db7ad886ec Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 2 Apr 2025 10:14:02 -0500 Subject: [PATCH 128/132] add pop_content, rename get_cell to get_content --- .../layouts/grid_layout.py | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 5d2be9b..957cb91 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -393,31 +393,63 @@ def add_content( if layout_cells: self._layout_cells() - def get_cell(self, cell_coordinates: Tuple[int, int]) -> displayio.Group: + def get_content(self, grid_position: Tuple[int, int]) -> displayio.Group: """ - Return a cells content based on the cell_coordinates. Raises + Return a cells content based on the grid_position. Raises KeyError if coordinates were not found in the GridLayout. - :param tuple cell_coordinates: the coordinates to lookup in the grid + :param tuple grid_position: the coordinates to lookup in the grid :return: the displayio content object at those coordinates """ for index, cell in enumerate(self._cell_content_list): # exact location 1x1 cell - if cell["grid_position"] == cell_coordinates: + if cell["grid_position"] == grid_position: return self._cell_content_list[index]["content"] # multi-spanning cell, any size bigger than 1x1 if ( cell["grid_position"][0] - <= cell_coordinates[0] + <= grid_position[0] < cell["grid_position"][0] + cell["cell_size"][0] and cell["grid_position"][1] - <= cell_coordinates[1] + <= grid_position[1] < cell["grid_position"][1] + cell["cell_size"][1] ): return self._cell_content_list[index]["content"] - raise KeyError(f"GridLayout does not contain cell at coordinates {cell_coordinates}") + raise KeyError(f"GridLayout does not contain content at coordinates {grid_position}") + + def pop_content(self, grid_position: Tuple[int, int]) -> None: + """ + Remove and return a cells content based on the grid_position. Raises + KeyError if coordinates were not found in the GridLayout. + + :param tuple grid_position: the coordinates to lookup in the grid + :return: the displayio content object at those coordinates + """ + for index, cell in enumerate(self._cell_content_list): + # exact location 1x1 cell + if cell["grid_position"] == grid_position: + _found = self._cell_content_list.pop(index) + self._layout_cells() + self.remove(_found["content"]) + return _found["content"] + + # multi-spanning cell, any size bigger than 1x1 + if ( + cell["grid_position"][0] + <= grid_position[0] + < cell["grid_position"][0] + cell["cell_size"][0] + and cell["grid_position"][1] + <= grid_position[1] + < cell["grid_position"][1] + cell["cell_size"][1] + ): + _found = self._cell_content_list.pop(index) + self._layout_cells() + self.remove(_found["content"]) + return _found["content"] + + raise KeyError(f"GridLayout does not contain content at coordinates {grid_position}") @property def cell_size_pixels(self) -> Tuple[int, int]: From e655978e468482b2f431630ee6dbeaddee3a60fb Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 30 May 2025 11:41:02 -0500 Subject: [PATCH 129/132] displayio api updates --- adafruit_displayio_layout/layouts/tab_layout.py | 5 +++-- adafruit_displayio_layout/widgets/flip_input.py | 8 +++++--- adafruit_displayio_layout/widgets/icon_animated.py | 6 +++--- requirements.txt | 1 + 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/adafruit_displayio_layout/layouts/tab_layout.py b/adafruit_displayio_layout/layouts/tab_layout.py index ac5875d..84f70fb 100644 --- a/adafruit_displayio_layout/layouts/tab_layout.py +++ b/adafruit_displayio_layout/layouts/tab_layout.py @@ -28,6 +28,7 @@ from adafruit_bitmap_font.bdf import BDF from adafruit_bitmap_font.pcf import PCF + from circuitpython_typing.displayio import AnyDisplay from fontio import BuiltinFont except ImportError: pass @@ -53,7 +54,7 @@ class TabLayout(displayio.Group): :param int x: x location the layout should be placed. Pixel coordinates. :param int y: y location the layout should be placed. Pixel coordinates. - :param displayio.Display display: The Display object to show the tab layout on. + :param AnyDisplay display: The Display object to show the tab layout on. :param int tab_text_scale: Size of the text shown in the tabs. Whole numbers 1 and greater are valid :param Optional[Union[BuiltinFont, BDF, PCF]] custom_font: A pre-loaded font object to use @@ -75,7 +76,7 @@ def __init__( self, x: int = 0, y: int = 0, - display: Optional[displayio.Display] = None, + display: Optional[AnyDisplay] = None, tab_text_scale: int = 1, custom_font: Optional[Union[BuiltinFont, BDF, PCF]] = terminalio.FONT, inactive_tab_spritesheet: Optional[str] = None, diff --git a/adafruit_displayio_layout/widgets/flip_input.py b/adafruit_displayio_layout/widgets/flip_input.py index cbdae52..83156dc 100644 --- a/adafruit_displayio_layout/widgets/flip_input.py +++ b/adafruit_displayio_layout/widgets/flip_input.py @@ -38,6 +38,8 @@ try: from typing import Any, List, Optional, Tuple + + from circuitpython_typing.displayio import AnyDisplay except ImportError: pass @@ -54,7 +56,7 @@ class FlipInput(Widget, Control): :param int x: pixel position :param int y: pixel position - :param displayio.Display display: the display where the widget will be displayed + :param AnyDisplay display: the display where the widget will be displayed :param value_list: the list of strings that will be displayed :type value_list: List[str] :param Font font: the font used for the text (defaults to ``terminalio.FONT``) @@ -87,7 +89,7 @@ class FlipInput(Widget, Control): def __init__( self, - display: displayio.Display, + display: AnyDisplay, *, value_list: List[str], font: FONT = FONT, @@ -586,7 +588,7 @@ def _blit_constrained( # _animate_bitmap - performs animation of scrolling between two bitmaps def _animate_bitmap( - display: displayio.Display, + display: AnyDisplay, target_bitmap: displayio.Bitmap, bitmap1: displayio.Bitmap, bitmap1_offset: Tuple[int, int], diff --git a/adafruit_displayio_layout/widgets/icon_animated.py b/adafruit_displayio_layout/widgets/icon_animated.py index 2e43821..f63fd25 100644 --- a/adafruit_displayio_layout/widgets/icon_animated.py +++ b/adafruit_displayio_layout/widgets/icon_animated.py @@ -37,7 +37,7 @@ try: from typing import Any, Optional, Tuple - from busdisplay import BusDisplay + from circuitpython_typing.displayio import AnyDisplay except ImportError: pass @@ -86,7 +86,7 @@ class IconAnimated(IconWidget): @classmethod def init_class( cls, - display: Optional[BusDisplay], + display: Optional[AnyDisplay], max_scale: float = 1.5, max_icon_size: Tuple[int, int] = (80, 80), max_color_depth: int = 256, @@ -100,7 +100,7 @@ def init_class( ``IconAnimated.init_class(display=board.DISPLAY, max_scale=1.5, max_icon_size=(80,80), max_color_depth=256)`` - :param displayio.Display display: The display where the icons will be displayed. + :param AnyDisplay display: The display where the icons will be displayed. :param float max_scale: The maximum zoom of the any of the icons, should be >= 1.0, (default: 1.5) :param max_icon_size: The maximum (x,y) pixel dimensions of any `IconAnimated` bitmap size diff --git a/requirements.txt b/requirements.txt index 1cfb615..433415f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ adafruit-circuitpython-bitmap-font adafruit-circuitpython-display-text adafruit-circuitpython-imageload adafruit-circuitpython-display-shapes +adafruit-circuitpython-typing From 5d089bc557813a5624e6d3e6bac6c9e9777bd0ff Mon Sep 17 00:00:00 2001 From: Shubham Patel <165564832+shubham0x13@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:49:05 +0530 Subject: [PATCH 130/132] Add anchor method --- adafruit_displayio_layout/layouts/__init__.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/adafruit_displayio_layout/layouts/__init__.py b/adafruit_displayio_layout/layouts/__init__.py index e69de29..7d9f684 100644 --- a/adafruit_displayio_layout/layouts/__init__.py +++ b/adafruit_displayio_layout/layouts/__init__.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 Shubham Patel +# +# SPDX-License-Identifier: MIT + +from micropython import const + +try: + from typing import Tuple +except ImportError: + pass + +# Anchor point constants for anchor method. +ANCHOR_TOP_LEFT = const((0.0, 0.0)) +ANCHOR_TOP_CENTER = const((0.5, 0.0)) +ANCHOR_TOP_RIGHT = const((1.0, 0.0)) +ANCHOR_CENTER_LEFT = const((0.0, 0.5)) +ANCHOR_CENTER = const((0.5, 0.5)) +ANCHOR_CENTER_RIGHT = const((1.0, 0.5)) +ANCHOR_BOTTOM_LEFT = const((0.0, 1.0)) +ANCHOR_BOTTOM_CENTER = const((0.5, 1.0)) +ANCHOR_BOTTOM_RIGHT = const((1.0, 1.0)) + + +def anchor(obj, anchor: Tuple[float, float], width: int, height: int) -> None: + """Helper to position a display object on screen using a defined anchor point. + + Sets `anchor_point` and `anchored_position` for display elements such as `Label`, + `Widget`, `AnchoredTileGrid`, or `AnchoredGroup`. + + :param obj: The object to be positioned. Must support `anchor_point` and `anchored_position`. + :param anchor: One of the predefined anchor constants (e.g. ANCHOR_TOP_LEFT, ANCHOR_CENTER) + :param width: Width of the display in pixels + :param height: Height of the display in pixels + """ + if not hasattr(obj, "anchor_point") or not hasattr(obj, "anchored_position"): + raise AttributeError( + "Object must have both `anchor_point` and `anchored_position` attributes." + ) + + if anchor not in { + ANCHOR_TOP_LEFT, + ANCHOR_TOP_CENTER, + ANCHOR_TOP_RIGHT, + ANCHOR_CENTER_LEFT, + ANCHOR_CENTER, + ANCHOR_CENTER_RIGHT, + ANCHOR_BOTTOM_LEFT, + ANCHOR_BOTTOM_CENTER, + ANCHOR_BOTTOM_RIGHT, + }: + raise ValueError( + "Anchor must be one of: ANCHOR_TOP_LEFT, ANCHOR_TOP_CENTER, ANCHOR_TOP_RIGHT,\n" + "ANCHOR_CENTER_LEFT, ANCHOR_CENTER, ANCHOR_CENTER_RIGHT,\n" + "ANCHOR_BOTTOM_LEFT, ANCHOR_BOTTOM_CENTER, ANCHOR_BOTTOM_RIGHT." + ) + + obj.anchor_point = anchor + obj.anchored_position = ( + int(anchor[0] * width), + int(anchor[1] * height), + ) From cfb3f13e9fffb3e2c28a04eb633f2f53608750f3 Mon Sep 17 00:00:00 2001 From: Shubham Patel <165564832+shubham0x13@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:16:35 +0530 Subject: [PATCH 131/132] Add bounds check in add_content --- adafruit_displayio_layout/layouts/grid_layout.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 957cb91..15cfd09 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -378,6 +378,15 @@ def add_content( then the cell_anchor_point from the GridLayout will be used. :return: None""" + grid_x = grid_position[0] + grid_y = grid_position[1] + max_grid_x = self.grid_size[0] + max_grid_y = self.grid_size[1] + if grid_x >= max_grid_x or grid_y >= max_grid_y: + raise ValueError( + f"Grid position {grid_position} is out of bounds for grid size {self.grid_size}" + ) + if cell_anchor_point: _this_cell_anchor_point = cell_anchor_point else: From 74411706db2f863ced498925409b4060a99492c2 Mon Sep 17 00:00:00 2001 From: Shubham Patel <165564832+shubham0x13@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:23:46 +0530 Subject: [PATCH 132/132] Simplify grid bounds unpacking --- adafruit_displayio_layout/layouts/grid_layout.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/adafruit_displayio_layout/layouts/grid_layout.py b/adafruit_displayio_layout/layouts/grid_layout.py index 15cfd09..b57bd16 100644 --- a/adafruit_displayio_layout/layouts/grid_layout.py +++ b/adafruit_displayio_layout/layouts/grid_layout.py @@ -378,10 +378,8 @@ def add_content( then the cell_anchor_point from the GridLayout will be used. :return: None""" - grid_x = grid_position[0] - grid_y = grid_position[1] - max_grid_x = self.grid_size[0] - max_grid_y = self.grid_size[1] + grid_x, grid_y = grid_position + max_grid_x, max_grid_y = self.grid_size if grid_x >= max_grid_x or grid_y >= max_grid_y: raise ValueError( f"Grid position {grid_position} is out of bounds for grid size {self.grid_size}"