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: Mandatory keyword only argument:
* `elements` A list or tuple of strings to display. Must have at least one * `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: Optional keyword only arguments:
* `width=None` Control width in pixels. By default this is calculated to * `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 specified to the constructor. The currently selected item may be retrieved by
means of the instance's `value` or `textvalue` methods. 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) ###### [Contents](./README.md#0-contents)
# 14. DialogBox class # 14. DialogBox class

Wyświetl plik

@ -5,34 +5,40 @@
import hardware_setup # Create a display instance import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd 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.core.writer import CWriter
from gui.widgets.menu import Menu from gui.widgets.menu import Menu
from gui.widgets.buttons import CloseButton from gui.widgets.buttons import CloseButton
from gui.core.colors import * from gui.core.colors import *
from gui.widgets.dialog import DialogBox
class BaseScreen(Screen): class BaseScreen(Screen):
def __init__(self): def __init__(self):
def cb(button, n): def cb(button, n):
print('Top level callback', n) print('Help callback', n)
def cb_sm(lb, 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) print('Submenu callback', lb.value(), lb.textvalue(), n)
if lb.value() == 0:
Screen.change(DialogBox, kwargs = kwargs)
super().__init__() super().__init__()
mnu = (('Gas', cb_sm, (0,), ('Helium','Neon','Argon','Krypton','Xenon','Radon')), mnu = (('Gas', (('Helium', cb_sm, (0,)),
('Metal', cb_sm, (1,), ('Lithium', 'Sodium', 'Potassium','Rubidium','Caesium')), ('Neon', cb_sm, (1,)),
('View', cb, (2,))) ('Argon', cb_sm, (2,)),
wri = CWriter(ssd, freesans20, GREEN, BLACK, verbose=False) ('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) Menu(wri, bgcolor=BLUE, textcolor=WHITE, args = mnu)
CloseButton(wri) 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 self.entry_height = writer.height + 2 # Allow a pixel above and below text
height = self.entry_height 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 if width is None: # Allow for square at end for arrow
self.textwidth = max(writer.stringlen(s) for s in elements) self.textwidth = max(writer.stringlen(s) for s in elements)
width = self.textwidth + 2 + height width = self.textwidth + 2 + height
@ -88,3 +97,7 @@ class Dropdown(Widget):
if len(self.elements) > 1: if len(self.elements) > 1:
args = (self.writer, self.row - 2, self.col - 2, self) args = (self.writer, self.row - 2, self.col - 2, self)
Screen.change(_ListDialog, args = args) 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 # handled by Screen .move bound method
class SubMenu(Window): 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 wri = menu.writer
row = button.height + 2 row = button.height + 2
col = button.col # Drop down below top level menu button col = button.col # Drop down below top level menu button
# Need to determine Window dimensions from size of Listbox, which # Need to determine Window dimensions from size of Listbox, which
# depends on number and length of elements. # 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 lb_width = textwidth + 2
# Calculate Window dimensions # Calculate Window dimensions
ap_height = lb_height + 6 # Allow for listbox border ap_height = lb_height + 6 # Allow for listbox border
ap_width = lb_width + 6 ap_width = lb_width + 6
super().__init__(row, col, ap_height, ap_width) super().__init__(row, col, ap_height, ap_width)
self.listbox = Listbox(wri, row + 3, col + 3, elements = elements, width = lb_width, Listbox(wri, row + 3, col + 3, elements = te, width = lb_width,
fgcolor = button.fgcolor, bgcolor = button.bgcolor, bdcolor=False, fgcolor = button.fgcolor, bgcolor = button.bgcolor, bdcolor=False,
fontcolor = button.textcolor, select_color = menu.select_color, fontcolor = button.textcolor, select_color = menu.select_color,
callback = self.callback) callback = self.callback)
self.cb = cb
self.args = args
def callback(self, obj_listbox): def callback(self, lbox):
Screen.back() 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 # 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 # 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: 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.writer = writer
self.select_color = select_color self.select_color = select_color
row = 2 row = 2
@ -54,8 +64,8 @@ class Menu:
'height' : height, 'height' : height,
'textcolor' : textcolor, } 'textcolor' : textcolor, }
for arg in args: for arg in args:
if len(arg) == 4: # Handle submenu if len(arg) == 2: # Handle submenu
# txt, cb, (cbargs,), (elements,) = arg # txt, ((element, cb, (cbargs,)),(element,cb, (cbargs,)), ..) = arg
b = Button(writer, row, col, text=arg[0], b = Button(writer, row, col, text=arg[0],
callback=self.cb, args=arg, **btn) callback=self.cb, args=arg, **btn)
else: else:
@ -64,6 +74,6 @@ class Menu:
callback=cb, args=cbargs, **btn) callback=cb, args=cbargs, **btn)
col = b.mcol col = b.mcol
def cb(self, button, txt, user_cb, args, elements): # Button pushed which calls submenu def cb(self, button, txt, elements): # Button pushed which calls submenu
args = (self, button, elements, user_cb, args) args = (self, button, elements)
Screen.change(SubMenu, args = args) 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 prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control
increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease 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)