From ccaa1d1797c35c4d493fe6b4be19eb269b203bf1 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Thu, 8 Jul 2021 13:18:05 +0100 Subject: [PATCH] Squash bugs in Pushbutton and ScaleLog widgets. --- README.md | 16 ++++++++-------- gui/core/ugui.py | 3 ++- gui/demos/tstat.py | 15 ++++++++------- gui/widgets/buttons.py | 19 ++++++------------- gui/widgets/scale_log.py | 4 ++-- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 25d20d5..d1a87a9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ # micropython-micro-gui -This is a lightweight, portable, MicroPython GUI library for displays with -drivers subclassed from `framebuf`. It allows input via pushbuttons or via a -switch joystick. Written in Python it runs under a standard MicroPython -firmware build. +This is a lightweight, portable, MicroPython GUI library for displays having +drivers subclassed from `framebuf`. Written in Python it runs under a standard +MicroPython firmware build. Options for data input comprise + * Via from two to five pushbuttons depending on the application. + * Via a switch-based navigation joystick. + * Via two pushbuttons and a rotary encoder such as +[this one](https://www.adafruit.com/product/377). It is larger and more complex than `nano-gui` owing to the support for input. It enables switching between screens and launching modal windows. In addition @@ -19,9 +22,6 @@ to a wide range of displays. It is also portable between hosts. ![Image](./images/ttgo.JPG) TTGO T-Display. Add a joystick switch and an SIL resistor for a simple, inexpensive, WiFi capable system. -An alternative interface consists of two pushbuttons and an encoder such as -[this one](https://www.adafruit.com/product/377). - # Rationale Touch GUI's have many advantages, however they have drawbacks, principally cost @@ -30,7 +30,7 @@ and the need for calibration (although the factory calibrated). Another problem is that there are various types of touch controller, magnifying the difficulty of writing a portable GUI. -Pushbutton input works well and yields astonishingly low cost solutions. A +The input options work well and yield astonishingly low cost solutions. A network-connected board with a 135x240 color display can be built for under £20 ($20?) using the [TTGO T-Display](http://www.lilygo.cn/prod_view.aspx?TypeId=50044&Id=1126). The diff --git a/gui/core/ugui.py b/gui/core/ugui.py index 514f2bd..6ae7b65 100644 --- a/gui/core/ugui.py +++ b/gui/core/ugui.py @@ -539,7 +539,8 @@ class Widget: self.draw = True # Signals that obect must be redrawn self._value = value - # Current colors + # Set colors. Writer colors cannot be None: + # bg == 0, fg == 1 are ultimate (monochrome) defaults. if fgcolor is None: fgcolor = writer.fgcolor if bgcolor is None: diff --git a/gui/demos/tstat.py b/gui/demos/tstat.py index 3f03dee..67a5854 100644 --- a/gui/demos/tstat.py +++ b/gui/demos/tstat.py @@ -25,9 +25,10 @@ from gui.core.colors import * class BaseScreen(Screen): def __init__(self): - def btncb(btn, reg, low, high): + def btncb(btn, reg, low, high): # Button callbck reg.adjust(low, high) - def rats(btn, ts, reg): + + def delete_alarm(btn, ts, reg): ts.del_region(reg) super().__init__() @@ -39,7 +40,7 @@ class BaseScreen(Screen): legends=('0.0', '0.5', '1.0')) self.ts = Tstat(wri, row, sl.mcol + 5, divisions = 4, ptcolor=YELLOW, height=100, width=15, style=Tstat.BAR, legends=('0.0', '0.5', '1.0')) - reg = Region(self.ts, 0.4, 0.6, MAGENTA, self.ts_cb) + reg = Region(self.ts, 0.4, 0.55, MAGENTA, self.ts_cb) al = Region(self.ts, 0.9, 1.0, RED, self.al_cb) col = self.ts.mcol + 5 self.lbl = Label(wri, row, col, 35, bdcolor=RED, bgcolor=BLACK) @@ -48,14 +49,14 @@ class BaseScreen(Screen): self.grn = LED(wri, self.led.mrow + 5, col, height=20, color=GREEN, bdcolor=BLACK) col = self.lbl.mcol + 5 btn = Button(wri, row + 30, col, width=0, - text='down', litcolor=RED, bgcolor=DARKGREEN, + text='down', litcolor=RED, callback=btncb, args=(reg, 0.2, 0.3)) btn1 = Button(wri, btn.mrow + 5, col, width=btn.width, - text='up', litcolor=RED, bgcolor=DARKGREEN, + text='up', litcolor=RED, callback=btncb, args=(reg, 0.5, 0.6)) Button(wri, btn1.mrow + 5, col, width=btn.width, - text='del', litcolor=RED, bgcolor=DARKGREEN, - callback=rats, args=(self.ts, al)) + text='del', litcolor=RED, + callback=delete_alarm, args=(self.ts, al)) CloseButton(wri) def after_open(self): diff --git a/gui/widgets/buttons.py b/gui/widgets/buttons.py index c890b8e..94af448 100644 --- a/gui/widgets/buttons.py +++ b/gui/widgets/buttons.py @@ -25,18 +25,14 @@ class Button(Widget): super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False, True) self.shape = shape self.radius = height // 2 - self.fill = bgcolor is not None # Draw background if color specified self.litcolor = litcolor self.textcolor = self.fgcolor if textcolor is None else textcolor - self.orig_fgcolor = self.fgcolor - self.orig_bgcolor = self.bgcolor self.text = text self.callback = callback self.callback_args = args self.onrelease = onrelease if self.litcolor is not None: self.delay = Delay_ms(self.shownormal) - self.litcolor = litcolor if self.fgcolor is not None else None def show(self): if self.screen is not Screen.current_screen: @@ -53,8 +49,7 @@ class Button(Widget): if self.shape == CIRCLE: # Button coords are of top left corner of bounding box x += self.radius y += self.radius - if self.fill: - display.fillcircle(x, y, self.radius, self.bgcolor) + display.fillcircle(x, y, self.radius, self.bgcolor) display.circle(x, y, self.radius, self.fgcolor) if len(self.text): display.print_centred(self.writer, x, y, self.text, self.textcolor, self.bgcolor) @@ -62,14 +57,12 @@ class Button(Widget): xc = x + w // 2 yc = y + h // 2 if self.shape == RECTANGLE: # rectangle - if self.fill: - display.fill_rect(x, y, w, h, self.bgcolor) + display.fill_rect(x, y, w, h, self.bgcolor) display.rect(x, y, w, h, self.fgcolor) if len(self.text): display.print_centred(self.writer, xc, yc, self.text, self.textcolor, self.bgcolor) elif self.shape == CLIPPED_RECT: # clipped rectangle - if self.fill: - display.fill_clip_rect(x, y, w, h, self.bgcolor) + display.fill_clip_rect(x, y, w, h, self.bgcolor) display.clip_rect(x, y, w, h, self.fgcolor) if len(self.text): display.print_centred(self.writer, xc, yc, self.text, self.textcolor, self.bgcolor) @@ -80,7 +73,7 @@ class Button(Widget): # control caused a screen change while timer running. while self.screen is not Screen.current_screen: await asyncio.sleep_ms(500) - self.bgcolor = self.orig_bgcolor + self.bgcolor = self.def_bgcolor self.draw = True # Redisplay def do_sel(self): # Select was pushed @@ -186,7 +179,7 @@ class RadioButtons: self.lstbuttons.append(button) button.callback = self._callback active = len(self.lstbuttons) == self.selected + 1 - button.bgcolor = self.highlight if active else button.orig_bgcolor + button.bgcolor = self.highlight if active else button.def_bgcolor if active: self.current = button return button @@ -209,6 +202,6 @@ class RadioButtons: but.bgcolor = self.highlight self.current = button else: - but.bgcolor = but.orig_bgcolor + but.bgcolor = but.def_bgcolor but.draw = True self.user_callback(button, *args) # user gets button with args they specified diff --git a/gui/widgets/scale_log.py b/gui/widgets/scale_log.py index bb8437c..3341240 100644 --- a/gui/widgets/scale_log.py +++ b/gui/widgets/scale_log.py @@ -147,8 +147,8 @@ class ScaleLog(LinearIO): if isinstance(button, int): # Using an encoder delta = self.delta * self.encoder_rate * 0.1 if self.precision else self.delta * self.encoder_rate self.value(self.value() * (1 + delta)**val) - else: - asyncio.create_task(self.btnhan(button, val, d)) + else: # val == 1 or -1 + asyncio.create_task(self.btnhan(button, val)) async def btnhan(self, button, up): up = up == 1