Prior to listbox refactor.

pull/8/head
Peter Hinch 2021-07-14 16:42:08 +01:00
rodzic a9b0e90968
commit 70c0ea248e
5 zmienionych plików z 73 dodań i 31 usunięć

Wyświetl plik

@ -1256,7 +1256,7 @@ Constructor mandatory positional args:
Mandatory keyword only argument:
* `elements` A list or tuple of strings to display. Must have at least one
entry.
entry. See below for an alternative way to use the `Dropdown`.
Optional keyword only arguments:
* `width=None` Control width in pixels. By default this is calculated to
@ -1298,6 +1298,19 @@ The callback's first argument is the dropdown instance followed by any args
specified to the constructor. The currently selected item may be retrieved by
means of the instance's `value` or `textvalue` methods.
#### Alternative approach
By default the `Dropdown` runs a single callback regardless of the element
chosen. This can be changed by specifying `elements` such that each element
comprises a 3-list or 3-tuple with the following contents:
0. String to display.
1. Callback.
2. Tuple of args (may be ()).
In this case constructor args `callback` and `args` must not be supplied. Args
received by the callback functions comprise the `Dropdown` instance followed by
any supplied args.
###### [Contents](./README.md#0-contents)
# 14. DialogBox class

Wyświetl plik

@ -5,34 +5,40 @@
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd
import gui.fonts.freesans20 as freesans20
import gui.fonts.freesans20 as font
from gui.core.writer import CWriter
from gui.widgets.menu import Menu
from gui.widgets.buttons import CloseButton
from gui.core.colors import *
from gui.widgets.dialog import DialogBox
class BaseScreen(Screen):
def __init__(self):
def cb(button, n):
print('Top level callback', n)
print('Help callback', n)
def cb_sm(lb, n):
kwargs = {'writer' : wri, 'row': 60, 'col' : 2,
'elements' : (('Yes', GREEN), ('No', RED), ('Foo', YELLOW)),
'label' : 'Test dialog',
}
print('Submenu callback', lb.value(), lb.textvalue(), n)
if lb.value() == 0:
Screen.change(DialogBox, kwargs = kwargs)
super().__init__()
mnu = (('Gas', cb_sm, (0,), ('Helium','Neon','Argon','Krypton','Xenon','Radon')),
('Metal', cb_sm, (1,), ('Lithium', 'Sodium', 'Potassium','Rubidium','Caesium')),
('View', cb, (2,)))
wri = CWriter(ssd, freesans20, GREEN, BLACK, verbose=False)
mnu = (('Gas', (('Helium', cb_sm, (0,)),
('Neon', cb_sm, (1,)),
('Argon', cb_sm, (2,)),
('Krypton', cb_sm, (3,)),
('Xenon', cb_sm, (4,)),
('Radon', cb_sm, (5,)))),
('Metal',(('Lithium', cb_sm, (6,)),
('Sodium', cb_sm, (7,)),
('Potassium', cb_sm, (8,)),
('Rubidium', cb_sm, (9,)),
('More', (('Gold', cb_sm, (6,)),
('Silver', cb_sm, (7,)),
('Iron', cb_sm, (8,)),
('Zinc', cb_sm, (9,)),
('Copper', cb_sm, (10,)))))),
('Help', cb, (2,)))
wri = CWriter(ssd, font, GREEN, BLACK, verbose=False)
Menu(wri, bgcolor=BLUE, textcolor=WHITE, args = mnu)
CloseButton(wri)

Wyświetl plik

@ -41,6 +41,15 @@ class Dropdown(Widget):
self.entry_height = writer.height + 2 # Allow a pixel above and below text
height = self.entry_height
e0 = elements[0]
# Check whether elements specified as (str, str,...) or ([str, callback, args], [...)
if isinstance(e0, tuple) or isinstance(e0, list):
te = [x[0] for x in elements] # Copy text component
self.els = elements # Retain original
elements = te
if callback is not dolittle:
raise ValueError('Cannot specify callback.')
callback = self._despatch
if width is None: # Allow for square at end for arrow
self.textwidth = max(writer.stringlen(s) for s in elements)
width = self.textwidth + 2 + height
@ -88,3 +97,7 @@ class Dropdown(Widget):
if len(self.elements) > 1:
args = (self.writer, self.row - 2, self.col - 2, self)
Screen.change(_ListDialog, args = args)
def _despatch(self, _): # Run the callback specified in elements
x = self.els[self.value()]
x[1](self, *x[2])

Wyświetl plik

@ -16,35 +16,45 @@ from gui.core.colors import *
# handled by Screen .move bound method
class SubMenu(Window):
def __init__(self, menu, button, elements, cb, args): # menu is parent Menu
def __init__(self, menu, button, elements): # menu is parent Menu
self.menu = menu
self.button = button
wri = menu.writer
row = button.height + 2
col = button.col # Drop down below top level menu button
# Need to determine Window dimensions from size of Listbox, which
# depends on number and length of elements.
entry_height, lb_height, textwidth = Listbox.dimensions(wri, elements)
te = [x[0] for x in elements] # Text part
self.elements = elements
entry_height, lb_height, textwidth = Listbox.dimensions(wri, te)
lb_width = textwidth + 2
# Calculate Window dimensions
ap_height = lb_height + 6 # Allow for listbox border
ap_width = lb_width + 6
super().__init__(row, col, ap_height, ap_width)
self.listbox = Listbox(wri, row + 3, col + 3, elements = elements, width = lb_width,
fgcolor = button.fgcolor, bgcolor = button.bgcolor, bdcolor=False,
fontcolor = button.textcolor, select_color = menu.select_color,
callback = self.callback)
self.cb = cb
self.args = args
Listbox(wri, row + 3, col + 3, elements = te, width = lb_width,
fgcolor = button.fgcolor, bgcolor = button.bgcolor, bdcolor=False,
fontcolor = button.textcolor, select_color = menu.select_color,
callback = self.callback)
def callback(self, obj_listbox):
def callback(self, lbox):
Screen.back()
self.cb(obj_listbox, *self.args) # CB can access obj_listbox.value() or .textvalue()
el = self.elements[lbox.value()] # (text, cb, args)
if len(el) == 2: # Recurse into submenu
args = (self.menu, self.button, el[1])
Screen.change(SubMenu, args = args)
else:
el[1](lbox, *el[2])
# A Menu is a set of Button objects at the top of the screen. On press, Buttons either run the
# user callback or instantiate a SubMenu
# args: ((text, cb, (args,)),(text, cb, (args,), (elements,)), ...)
# args is a list comprising items which may be a mixture of two types
# Single items: (top_text, cb, (args, ...))
# Submenus: (top_text, ((mnu_text, cb, (args, ...)),(mnu_text, cb, (args, ...)),...)
class Menu:
def __init__(self, writer, *, height=25, bgcolor=None, fgcolor=None, textcolor=None, select_color=DARKBLUE, args):
def __init__(self, writer, *, height=25, bgcolor=None, fgcolor=None,
textcolor=None, select_color=DARKBLUE, args):
self.writer = writer
self.select_color = select_color
row = 2
@ -54,8 +64,8 @@ class Menu:
'height' : height,
'textcolor' : textcolor, }
for arg in args:
if len(arg) == 4: # Handle submenu
# txt, cb, (cbargs,), (elements,) = arg
if len(arg) == 2: # Handle submenu
# txt, ((element, cb, (cbargs,)),(element,cb, (cbargs,)), ..) = arg
b = Button(writer, row, col, text=arg[0],
callback=self.cb, args=arg, **btn)
else:
@ -64,6 +74,6 @@ class Menu:
callback=cb, args=cbargs, **btn)
col = b.mcol
def cb(self, button, txt, user_cb, args, elements): # Button pushed which calls submenu
args = (self, button, elements, user_cb, args)
def cb(self, button, txt, elements): # Button pushed which calls submenu
args = (self, button, elements)
Screen.change(SubMenu, args = args)

Wyświetl plik

@ -51,4 +51,4 @@ sel = Pin(16, Pin.IN, Pin.PULL_UP) # Operate current control
prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control
increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
display = Display(ssd, nxt, sel, prev, increase, decrease) #, 5)
display = Display(ssd, nxt, sel, prev, increase, decrease, 5)