From 094d24973b160b595dbdb8793ad2f0862c595ae9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 26 Mar 2022 15:08:46 -0500 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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)