Add FloatAdj to widgets/adjuster.py

pull/8/head
Peter Hinch 2021-11-09 11:46:59 +00:00
rodzic 35064c3501
commit 5c7d6c96b3
3 zmienionych plików z 78 dodań i 20 usunięć

Wyświetl plik

@ -2348,6 +2348,16 @@ subclass. The callback runs when the widget is instantiated and whenever the
value changes. Typically the callback will adjust the text displayed on a value changes. Typically the callback will adjust the text displayed on a
linked label. linked label.
### A numeric entry device
The file [widgets/adjuster.py](./gui/widgets/adjuster.py) includes an example
class which combines an `Adjuster` with one or two `Label` instances. The
`Adjuster` changes the displayed value in the `Label` to its left. Its use is
illustrated in [demos/adjuster.py](./gui/demos/adjuster.py). The class can be
used as a template for a user class, which may have a different layout on
screen. It supports arbitrary mapping and number formatting on a per-instance
basis. See code comments for further details.
###### [Contents](./README.md#0-contents) ###### [Contents](./README.md#0-contents)
# 23 Menu class # 23 Menu class

Wyświetl plik

@ -9,7 +9,7 @@ from gui.core.ugui import Screen, ssd
from gui.widgets.label import Label from gui.widgets.label import Label
from gui.widgets.buttons import CloseButton from gui.widgets.buttons import CloseButton
from gui.widgets.adjuster import Adjuster from gui.widgets.adjuster import Adjuster, FloatAdj
from gui.core.writer import CWriter from gui.core.writer import CWriter
# Font for CWriter # Font for CWriter
@ -18,7 +18,6 @@ from gui.core.colors import *
class BaseScreen(Screen): class BaseScreen(Screen):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -26,33 +25,43 @@ class BaseScreen(Screen):
col = 2 col = 2
row = 2 row = 2
self.lbl1 = Label(wri, row, col, 60, bdcolor=RED) self.lbl1 = Label(wri, row, col, 60, bdcolor=RED)
a = Adjuster(wri, row, self.lbl1.mcol + 2, fgcolor=RED, callback=self.adj1_callback) a = Adjuster(wri, row, self.lbl1.mcol + 2, fgcolor=RED,
Label(wri, row, a.mcol + 2, "Simple") callback=self.adj1_callback)
Label(wri, row, a.mcol + 2, "0-1")
row = self.lbl1.mrow + 5 row = self.lbl1.mrow + 5
self.lbl2 = Label(wri, row, col, 60, bdcolor=RED) self.lbl2 = Label(wri, row, col, 60, bdcolor=RED)
a =Adjuster(wri, row, self.lbl2.mcol + 2, fgcolor=RED, value=0.5, callback=self.adj2_callback) a = Adjuster(wri, row, self.lbl2.mcol + 2,
fgcolor=RED, value=0.5,
callback=self.adj2_callback)
Label(wri, row, a.mcol + 2, "Scale") Label(wri, row, a.mcol + 2, "Scale")
row = self.lbl2.mrow + 5 row = self.lbl2.mrow + 5
self.lbl3 = Label(wri, row, col, 60, bdcolor=YELLOW) self.lbl3 = Label(wri, row, col, 60, bdcolor=YELLOW)
a = Adjuster(wri, row, self.lbl3.mcol + 2, fgcolor=YELLOW, callback=self.adj3_callback) a = Adjuster(wri, row, self.lbl3.mcol + 2, fgcolor=YELLOW,
callback=self.adj3_callback)
Label(wri, row, a.mcol + 2, "Log") Label(wri, row, a.mcol + 2, "Log")
self.fa = FloatAdj(wri, a.mrow + 5, col, color=BLUE,
map_func=lambda x: (x - 0.5) * 20,
fstr="{:6.2f}", text="class")
CloseButton(wri) # Quit the application CloseButton(wri) # Quit the application
def adj1_callback(self, adj): def adj1_callback(self, adj):
v = adj.value() # Typically do mapping here v = adj.value() # Typically do mapping here
self.lbl1.value(f'{v:4.2f}') self.lbl1.value(f"{v:4.2f}")
def adj2_callback(self, adj): def adj2_callback(self, adj):
v = (adj.value() - 0.5) * 10 # Scale and offset v = (adj.value() - 0.5) * 10 # Scale and offset
self.lbl2.value(f'{v:4.2f}') self.lbl2.value(f"{v:4.2f}")
def adj3_callback(self, adj): def adj3_callback(self, adj):
v = 10 ** (3 * adj.value()) # Log 3 decades v = 10 ** (3 * adj.value()) # Log 3 decades
self.lbl3.value(f'{v:4.2f}') self.lbl3.value(f"{v:4.2f}")
#def after_open(self): # Demo of programmatic change
#self.fa.value(0.5)
def test(): def test():
print('Demo of Adjuster control.') print("Demo of Adjuster control.")
Screen.change(BaseScreen) # A class is passed here, not an instance. Screen.change(BaseScreen) # A class is passed here, not an instance.
test() test()

Wyświetl plik

@ -4,21 +4,24 @@
# Copyright (c) 2021 Peter Hinch # Copyright (c) 2021 Peter Hinch
from gui.core.ugui import LinearIO, display from gui.core.ugui import LinearIO, display
from gui.widgets.label import Label
import math import math
TWOPI = 2 * math.pi TWOPI = 2 * math.pi
# Null function # Null function
dolittle = lambda *_ : None dolittle = lambda *_: None
# *********** CONTROL KNOB CLASS *********** # *********** CONTROL KNOB CLASS ***********
class Adjuster(LinearIO): class Adjuster(LinearIO):
def __init__(self, writer, row, col, *, value=0.0, def __init__(self, writer, row, col, *,
fgcolor=None, bgcolor=None, color=None, prcolor=None, value=0.0, fgcolor=None, bgcolor=None, color=None,
callback=dolittle, args=[]): prcolor=None, callback=dolittle, args=[]):
height = writer.height # Match a user-linked Label height = writer.height # Match a user-linked Label
super().__init__(writer, row, col, height, height, fgcolor, super().__init__(writer, row, col, height, height,
bgcolor, False, value, True, prcolor) fgcolor, bgcolor, False, value,
True, prcolor)
super()._set_callbacks(callback, args) super()._set_callbacks(callback, args)
radius = height / 2 radius = height / 2
self.arc = 1.5 * math.pi # Usable angle of control self.arc = 1.5 * math.pi # Usable angle of control
@ -47,3 +50,39 @@ class Adjuster(LinearIO):
x_end = int(self.xorigin + length * math.sin(angle)) x_end = int(self.xorigin + length * math.sin(angle))
y_end = int(self.yorigin - length * math.cos(angle)) y_end = int(self.yorigin - length * math.cos(angle))
display.line(int(self.xorigin), int(self.yorigin), x_end, y_end, color) display.line(int(self.xorigin), int(self.yorigin), x_end, y_end, color)
# This class combines an Adjuster with one or two labels. Numerous layout
# options exist: users may wish to write their own versions of this example.
# The map_func enables instances to have their own mapping of Adjuster value
# to perform offset, scaling, log mapping etc.
# The object's value is that of the Adjuster, in range 0.0-1.0. The scaled
# value is retrieved with .mapped_value()
class FloatAdj:
def __init__(self, wri, row, col, *,
lbl_width=60, value=0.0, color=None,
fstr="{:4.2f}", map_func=lambda v: v, text="",
callback=dolittle, args=[]):
self.fstr = fstr
self.map_func = map_func
self.callback = callback
self.args = args
self.lbl = Label(wri, row, col, lbl_width, bdcolor=color)
self.adj = Adjuster(wri, row, self.lbl.mcol + 2, value=value,
fgcolor=color, callback=self.cb)
l = Label(wri, row, self.adj.mcol + 2, text) if text else self.adj
# Facilitate relative positioning.
self.mcol = l.mcol
self.mrow = self.adj.mrow
def cb(self, adj):
self.lbl.value(self.fstr.format(self.mapped_value(adj)))
self.callback(self, *self.args)
# Behave like a Widget.
def value(self, v=None):
return self.adj.value(v)
def mapped_value(self, adj=None): # Special handling for initial callback
return self.map_func(self.value() if adj is None else adj.value())