Closed petrkr closed 1 year ago
I'll investigate.
Thank you for the report. I've pushed an update which fixes this bug. It also throws a ValueError
if you attempt to open a window with no active widgets, because doing caused erroneous behaviour.
I will try to produce a fix to allow popup windows.
I will try, thanks. I have to do some dummy acrive widget to achieve that workflow where I really do not want user to interact and learn how to close those popup by program.
I will think about that "close" button at wifi connect screen, there maybe it could be, so user do not need wait timeout if already know that wifi does not in range.
But mostly I want that device to have standalone for "BFU" users who do can not broke many things by pressing buttons etc... It shall be terminal for peoples who are NOT programmers and have problem with basics.. I know it's hard to do software for this kind of users, but less buttons makes it better to them and mostly for support.
Imagine for example trezor, there is also screen, which sign transaction and user can not abort it during process... Lot of windows/linux dialogs also does not have allowed to interrupt by user, because it could lead to strange beaviours.
I will try to think how to do it...
But I want to have some prototype end of month (actually it's open source project, I have no benefit from it).
If I will not be able to it with microgui, I will try to do some Lite version (without menus, or draw menus like "press 1", "press 2"...) and base it on that.
Meanwhile regards and thanks
I should be able to produce something quickly.
What I have in mind is a subclass of Window
which requires no active widgets. Typically you'd populate it with one or more Label
instances. It would support a close
method so that a coroutine could cause the popup to disappear with focus returning to the underlying Screen
.
I have pushed a version which supports popup widows. Example usage:
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd, Window
import uasyncio as asyncio
from gui.widgets.label import Label
from gui.widgets.buttons import Button, CloseButton
from gui.core.writer import CWriter
# Font for CWriter
import gui.fonts.arial10 as arial10
from gui.core.colors import *
class PopUp(Window):
def __init__(self, row, col, height, width):
wri = CWriter(ssd, arial10, WHITE, BLACK, False)
super().__init__(row, col, height, width, bgcolor = BLACK, fgcolor=YELLOW, writer=wri) # See README
Label(wri, 10, 10, "Popup window")
async def do_popup():
await asyncio.sleep(1)
Screen.change(PopUp, args=(2, 2, 124, 155))
await asyncio.sleep(2)
PopUp.close()
class TestScreen(Screen):
def __init__(self):
super().__init__()
wri = CWriter(ssd, arial10, WHITE, BLACK, False)
CloseButton(wri)
Label(wri, 20, 20, "Underneath")
self.reg_task(do_popup())
def after_open(self):
print("After open")
Screen.change(TestScreen)
Note that using after_open
to launch the popup won't produce the desired result. This is because after_open
also runs when an overlaying window is closed: the window underneath is re-displayed and after_open
runs a second time. This is by design.
Please let me know what you think.
Yes, it seems nice, also I can define textbox in this async.
async def do_bootscreen():
global wifi, rfid
await asyncio.sleep_ms(10)
writb = CWriter(ssd, arial10, GREEN, BLACK)
Screen.change(BootScreen, args=(2, 2, 124, 155, writb))
_tb = Textbox(writb, 42, 6, width=147, nlines=8)
print(" -- Mifare NFC")
_tb.append("Loading RFID")
await asyncio.sleep_ms(0)
from components.rfid import PN532_UART
from components.rfid.pn532mifareio import PN532MifareIO
uart2 = UART(2, 115200, tx = NFC_TX, rx=NFC_RX, timeout=100)
rfid = PN532_UART(uart2)
from utils.wifi_connect import WiFiConnect
wifi = WiFiConnect()
#wifi.events_add_connecting(self.wifi_cb_connecting)
#wifi.events_add_connected(self.wifi_cb_connected)
_tb.append("Connecting wifi")
await asyncio.sleep_ms(0)
wifi.connect()
_tb.append("Connected")
await asyncio.sleep(2)
BootScreen.close()
Just since WiFiConnect does not support asyncio, I can not use "connecting" callbacks as they do not refresh screen (of course). also "wc.connect" is blocking call.
I have to do some callbacks etc to let know main-screen about situation "wifi" connected, so it can continue to do some other init stages (like connect to server etc.)
But That I think I will do by some semaphor flags in While True in main app.
meanwhile I did this construct... Maybe in asyncio can be better way? But for my knowledge this is best what I did
def boot_done(self, obj):
self._boot_done = True
self._wifi = obj[0]
self._rfid = obj[1]
self.reg_task(self.main())
def after_open(self):
if not self._boot_done:
self.reg_task(do_bootscreen(self.boot_done))
The solution above is fine, but here is alternative:
from uasyncio import Event
async def main(evt):
await evt.wait()
# Code runs after BaseScreen initialisation is complete
class BaseScreen(Screen):
def __init__(self):
super().__init__()
# Code omitted
self.started = Event()
self.reg_task(main(self.started))
def after_open(self):
self.started.set()
Of course you could cheat and just issue await asyncio.sleep(1)
at the start of main()
on the assumption that screen show will be complete by then. But an Event
is nicer.
If I will do windows with only one button ("OK") then if I will use next/prev/inc/dec buttons. It will for every push call parent's after_open method
If there are more buttons, this does not happend
then Screen