kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
Squash bugs in Pushbutton and ScaleLog widgets.
rodzic
a75eda8e85
commit
ccaa1d1797
16
README.md
16
README.md
|
@ -1,9 +1,12 @@
|
||||||
# micropython-micro-gui
|
# micropython-micro-gui
|
||||||
|
|
||||||
This is a lightweight, portable, MicroPython GUI library for displays with
|
This is a lightweight, portable, MicroPython GUI library for displays having
|
||||||
drivers subclassed from `framebuf`. It allows input via pushbuttons or via a
|
drivers subclassed from `framebuf`. Written in Python it runs under a standard
|
||||||
switch joystick. Written in Python it runs under a standard MicroPython
|
MicroPython firmware build. Options for data input comprise
|
||||||
firmware build.
|
* 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 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
|
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.
|
||||||
 TTGO T-Display. Add a joystick switch and an SIL
|
 TTGO T-Display. Add a joystick switch and an SIL
|
||||||
resistor for a simple, inexpensive, WiFi capable system.
|
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
|
# Rationale
|
||||||
|
|
||||||
Touch GUI's have many advantages, however they have drawbacks, principally cost
|
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
|
factory calibrated). Another problem is that there are various types of touch
|
||||||
controller, magnifying the difficulty of writing a portable GUI.
|
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
|
network-connected board with a 135x240 color display can be built for under £20
|
||||||
($20?) using the
|
($20?) using the
|
||||||
[TTGO T-Display](http://www.lilygo.cn/prod_view.aspx?TypeId=50044&Id=1126). The
|
[TTGO T-Display](http://www.lilygo.cn/prod_view.aspx?TypeId=50044&Id=1126). The
|
||||||
|
|
|
@ -539,7 +539,8 @@ class Widget:
|
||||||
self.draw = True # Signals that obect must be redrawn
|
self.draw = True # Signals that obect must be redrawn
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
# Current colors
|
# Set colors. Writer colors cannot be None:
|
||||||
|
# bg == 0, fg == 1 are ultimate (monochrome) defaults.
|
||||||
if fgcolor is None:
|
if fgcolor is None:
|
||||||
fgcolor = writer.fgcolor
|
fgcolor = writer.fgcolor
|
||||||
if bgcolor is None:
|
if bgcolor is None:
|
||||||
|
|
|
@ -25,9 +25,10 @@ from gui.core.colors import *
|
||||||
class BaseScreen(Screen):
|
class BaseScreen(Screen):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
def btncb(btn, reg, low, high):
|
def btncb(btn, reg, low, high): # Button callbck
|
||||||
reg.adjust(low, high)
|
reg.adjust(low, high)
|
||||||
def rats(btn, ts, reg):
|
|
||||||
|
def delete_alarm(btn, ts, reg):
|
||||||
ts.del_region(reg)
|
ts.del_region(reg)
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -39,7 +40,7 @@ class BaseScreen(Screen):
|
||||||
legends=('0.0', '0.5', '1.0'))
|
legends=('0.0', '0.5', '1.0'))
|
||||||
self.ts = Tstat(wri, row, sl.mcol + 5, divisions = 4, ptcolor=YELLOW, height=100, width=15,
|
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'))
|
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)
|
al = Region(self.ts, 0.9, 1.0, RED, self.al_cb)
|
||||||
col = self.ts.mcol + 5
|
col = self.ts.mcol + 5
|
||||||
self.lbl = Label(wri, row, col, 35, bdcolor=RED, bgcolor=BLACK)
|
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)
|
self.grn = LED(wri, self.led.mrow + 5, col, height=20, color=GREEN, bdcolor=BLACK)
|
||||||
col = self.lbl.mcol + 5
|
col = self.lbl.mcol + 5
|
||||||
btn = Button(wri, row + 30, col, width=0,
|
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))
|
callback=btncb, args=(reg, 0.2, 0.3))
|
||||||
btn1 = Button(wri, btn.mrow + 5, col, width=btn.width,
|
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))
|
callback=btncb, args=(reg, 0.5, 0.6))
|
||||||
Button(wri, btn1.mrow + 5, col, width=btn.width,
|
Button(wri, btn1.mrow + 5, col, width=btn.width,
|
||||||
text='del', litcolor=RED, bgcolor=DARKGREEN,
|
text='del', litcolor=RED,
|
||||||
callback=rats, args=(self.ts, al))
|
callback=delete_alarm, args=(self.ts, al))
|
||||||
CloseButton(wri)
|
CloseButton(wri)
|
||||||
|
|
||||||
def after_open(self):
|
def after_open(self):
|
||||||
|
|
|
@ -25,18 +25,14 @@ class Button(Widget):
|
||||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False, True)
|
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False, True)
|
||||||
self.shape = shape
|
self.shape = shape
|
||||||
self.radius = height // 2
|
self.radius = height // 2
|
||||||
self.fill = bgcolor is not None # Draw background if color specified
|
|
||||||
self.litcolor = litcolor
|
self.litcolor = litcolor
|
||||||
self.textcolor = self.fgcolor if textcolor is None else textcolor
|
self.textcolor = self.fgcolor if textcolor is None else textcolor
|
||||||
self.orig_fgcolor = self.fgcolor
|
|
||||||
self.orig_bgcolor = self.bgcolor
|
|
||||||
self.text = text
|
self.text = text
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
self.callback_args = args
|
self.callback_args = args
|
||||||
self.onrelease = onrelease
|
self.onrelease = onrelease
|
||||||
if self.litcolor is not None:
|
if self.litcolor is not None:
|
||||||
self.delay = Delay_ms(self.shownormal)
|
self.delay = Delay_ms(self.shownormal)
|
||||||
self.litcolor = litcolor if self.fgcolor is not None else None
|
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
if self.screen is not Screen.current_screen:
|
if self.screen is not Screen.current_screen:
|
||||||
|
@ -53,7 +49,6 @@ class Button(Widget):
|
||||||
if self.shape == CIRCLE: # Button coords are of top left corner of bounding box
|
if self.shape == CIRCLE: # Button coords are of top left corner of bounding box
|
||||||
x += self.radius
|
x += self.radius
|
||||||
y += 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)
|
display.circle(x, y, self.radius, self.fgcolor)
|
||||||
if len(self.text):
|
if len(self.text):
|
||||||
|
@ -62,13 +57,11 @@ class Button(Widget):
|
||||||
xc = x + w // 2
|
xc = x + w // 2
|
||||||
yc = y + h // 2
|
yc = y + h // 2
|
||||||
if self.shape == RECTANGLE: # rectangle
|
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)
|
display.rect(x, y, w, h, self.fgcolor)
|
||||||
if len(self.text):
|
if len(self.text):
|
||||||
display.print_centred(self.writer, xc, yc, self.text, self.textcolor, self.bgcolor)
|
display.print_centred(self.writer, xc, yc, self.text, self.textcolor, self.bgcolor)
|
||||||
elif self.shape == CLIPPED_RECT: # clipped rectangle
|
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)
|
display.clip_rect(x, y, w, h, self.fgcolor)
|
||||||
if len(self.text):
|
if len(self.text):
|
||||||
|
@ -80,7 +73,7 @@ class Button(Widget):
|
||||||
# control caused a screen change while timer running.
|
# control caused a screen change while timer running.
|
||||||
while self.screen is not Screen.current_screen:
|
while self.screen is not Screen.current_screen:
|
||||||
await asyncio.sleep_ms(500)
|
await asyncio.sleep_ms(500)
|
||||||
self.bgcolor = self.orig_bgcolor
|
self.bgcolor = self.def_bgcolor
|
||||||
self.draw = True # Redisplay
|
self.draw = True # Redisplay
|
||||||
|
|
||||||
def do_sel(self): # Select was pushed
|
def do_sel(self): # Select was pushed
|
||||||
|
@ -186,7 +179,7 @@ class RadioButtons:
|
||||||
self.lstbuttons.append(button)
|
self.lstbuttons.append(button)
|
||||||
button.callback = self._callback
|
button.callback = self._callback
|
||||||
active = len(self.lstbuttons) == self.selected + 1
|
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:
|
if active:
|
||||||
self.current = button
|
self.current = button
|
||||||
return button
|
return button
|
||||||
|
@ -209,6 +202,6 @@ class RadioButtons:
|
||||||
but.bgcolor = self.highlight
|
but.bgcolor = self.highlight
|
||||||
self.current = button
|
self.current = button
|
||||||
else:
|
else:
|
||||||
but.bgcolor = but.orig_bgcolor
|
but.bgcolor = but.def_bgcolor
|
||||||
but.draw = True
|
but.draw = True
|
||||||
self.user_callback(button, *args) # user gets button with args they specified
|
self.user_callback(button, *args) # user gets button with args they specified
|
||||||
|
|
|
@ -147,8 +147,8 @@ class ScaleLog(LinearIO):
|
||||||
if isinstance(button, int): # Using an encoder
|
if isinstance(button, int): # Using an encoder
|
||||||
delta = self.delta * self.encoder_rate * 0.1 if self.precision else self.delta * self.encoder_rate
|
delta = self.delta * self.encoder_rate * 0.1 if self.precision else self.delta * self.encoder_rate
|
||||||
self.value(self.value() * (1 + delta)**val)
|
self.value(self.value() * (1 + delta)**val)
|
||||||
else:
|
else: # val == 1 or -1
|
||||||
asyncio.create_task(self.btnhan(button, val, d))
|
asyncio.create_task(self.btnhan(button, val))
|
||||||
|
|
||||||
async def btnhan(self, button, up):
|
async def btnhan(self, button, up):
|
||||||
up = up == 1
|
up = up == 1
|
||||||
|
|
Ładowanie…
Reference in New Issue