From c6cdf80800768599a30d6a61a67efc3d07033124 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Fri, 20 Sep 2024 09:15:32 +0100 Subject: [PATCH] README.md: Add design notes appendix. --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++ gui/demos/simple.py | 17 ++++++------ 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 020d59e..dda0907 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ under development so check for updates. [Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives, more on callbacks. [Appendix 2 Freezing bytecode](./README.md#appendix-2-freezing-bytecode) Optional way to save RAM. [Appendix 3 Cross compiling](./README.md#appendix-3-cross-compiling) Another way to save RAM. +[Appendix 4 GUI Design notes](./README.md#appendix-4-gui-design-notes) The reason for continuous refresh. # 1. Basic concepts @@ -3214,6 +3215,9 @@ another from occurring. ``` The demo `gui/demos/audio.py` provides example usage. +See [Appendix 4 GUI Design notes](./README.md#appendix-4-gui-design-notes) for +the reason for continuous refresh. + # 10 ePaper displays In general ePaper displays do not work well with micro-gui because refresh is @@ -3460,6 +3464,8 @@ changes. I also keep the display driver and `boolpalette.py` in the filesystem as I have experienced problems freezing display drivers - but feel free to experiment. +###### [Contents](./README.md#0-contents) + ## Appendix 3 Cross compiling This addresses the case where a memory error occurs on import. There are better @@ -3476,3 +3482,64 @@ This creates a file `ugui.mpy`. It is necessary to move, delete or rename If "incorrect mpy version" errors occur, the cross compiler should be recompiled. + +## Appendix 4 GUI Design notes + +A user (Toni Röyhy) raised the question of why refresh operates as a continuous +background task, even when nothing has changed on screen. The concern was that +it may result in needless power consumption. The following reasons apply: +* It enables applications to draw on the screen using FrameBuffer primitives +without the need to notify the GUI to perform a refresh. +* There is a mechanism for stopping refresh in those rare occasions when it is +necessary. +* Stopping refresh has no measurable effect on power consumption. This is +because `asyncio` continues to schedule tasks even if refresh is paused. Overall +CPU activity remains high. The following script may be used to confirm this. + +```py +import hardware_setup # Create a display instance +from gui.core.ugui import Screen, ssd + +from gui.widgets import Label, Button, CloseButton +from gui.core.writer import CWriter +import gui.fonts.arial10 as arial10 +from gui.core.colors import * +import asyncio + +async def refresh_and_stop(): + Screen.rfsh_start.set() # Allow refresh + Screen.rfsh_done.clear() # Enable completion flag + await Screen.rfsh_done.wait() # Wait for a refresh to end + Screen.rfsh_start.clear() # Prevent another. + print("Refresh stopped") + +def cby(_): + asyncio.create_task(refresh_and_stop()) + +def cbn(_): + Screen.rfsh_start.set() # Allow refresh + print("Refresh started.") + + +class BaseScreen(Screen): + def __init__(self): + + super().__init__() + wri = CWriter(ssd, arial10, GREEN, BLACK) + col = 2 + row = 2 + Label(wri, row, col, "Refresh test") + row = 50 + Button(wri, row, col, text="Stop", callback=cby) + col += 60 + Button(wri, row, col, text="Start", callback=cbn) + CloseButton(wri) # Quit + + +def test(): + print("Refresh test.") + Screen.change(BaseScreen) + +test() +``` +###### [Contents](./README.md#0-contents) diff --git a/gui/demos/simple.py b/gui/demos/simple.py index 4edf5a1..30b9b89 100644 --- a/gui/demos/simple.py +++ b/gui/demos/simple.py @@ -1,7 +1,7 @@ # simple.py Minimal micro-gui demo. # Released under the MIT License (MIT). See LICENSE. -# Copyright (c) 2021 Peter Hinch +# Copyright (c) 2021-2024 Peter Hinch # hardware_setup must be imported before other modules because of RAM use. import hardware_setup # Create a display instance @@ -16,26 +16,25 @@ from gui.core.colors import * class BaseScreen(Screen): - def __init__(self): - def my_callback(button, arg): - print('Button pressed', arg) + print("Button pressed", arg) super().__init__() - # verbose default indicates if fast rendering is enabled wri = CWriter(ssd, arial10, GREEN, BLACK) col = 2 row = 2 - Label(wri, row, col, 'Simple Demo') + Label(wri, row, col, "Simple Demo") row = 50 - Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',)) + Button(wri, row, col, text="Yes", callback=my_callback, args=("Yes",)) col += 60 - Button(wri, row, col, text='No', callback=my_callback, args=('No',)) + Button(wri, row, col, text="No", callback=my_callback, args=("No",)) CloseButton(wri) # Quit the application + def test(): - print('Simple demo: button presses print to REPL.') + print("Simple demo: button presses print to REPL.") Screen.change(BaseScreen) # A class is passed here, not an instance. + test()