diff --git a/gui/demos/menu.py b/gui/demos/menu.py new file mode 100644 index 0000000..ce5e633 --- /dev/null +++ b/gui/demos/menu.py @@ -0,0 +1,33 @@ +# menu.py micro-gui demo of Menu class + +# Released under the MIT License (MIT). See LICENSE. +# Copyright (c) 2021 Peter Hinch + +import hardware_setup # Create a display instance +from gui.core.ugui import Screen, ssd +import gui.fonts.freesans20 as freesans20 +from gui.core.writer import CWriter + +from gui.widgets.menu import Menu +from gui.widgets.buttons import CloseButton +from gui.core.colors import * + +class BaseScreen(Screen): + + def __init__(self): + def cb(button, n): + print('Top level callback', n) + + def cb_sm(lb, n): + print('Submenu callback', lb.value(), lb.textvalue(), n) + + super().__init__() + mnu = (('Gas', cb_sm, (0,), ('Argon','Neon','Xenon','Radon')), + ('Metal', cb_sm, (1,), ('Caesium', 'Lithium', 'Sodium', 'Potassium')), + ('View', cb, (2,))) + wri = CWriter(ssd, freesans20, GREEN, BLACK, verbose=False) + Menu(wri, bgcolor=BLUE, textcolor=WHITE, args = mnu) + CloseButton(wri) + + +Screen.change(BaseScreen) diff --git a/gui/widgets/dropdown.py b/gui/widgets/dropdown.py index 78cef2b..3ee80f1 100644 --- a/gui/widgets/dropdown.py +++ b/gui/widgets/dropdown.py @@ -14,26 +14,24 @@ dolittle = lambda *_ : None # handled by Screen .move bound method class _ListDialog(Window): - def __init__(self, writer, row, col, dropdown, textwidth): - dd = dropdown - elements = dd.elements + def __init__(self, writer, row, col, dd): # dd is parent dropdown # Need to determine Window dimensions from size of Listbox, which # depends on number and length of elements. - entry_height, lb_height, textwidth = Listbox.dimensions(writer, elements) + entry_height, lb_height, textwidth = Listbox.dimensions(writer, dd.elements) 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(writer, row + 3, col + 3, elements = elements, width = lb_width, + self.listbox = Listbox(writer, row + 3, col + 3, elements = dd.elements, width = lb_width, fgcolor = dd.fgcolor, bgcolor = dd.bgcolor, bdcolor=False, fontcolor = dd.fontcolor, select_color = dd.select_color, value = dd.value(), callback = self.callback) - self.dropdown = dd + self.dd = dd def callback(self, obj_listbox): Screen.back() - self.dropdown.value(obj_listbox.value()) # Update it + self.dd.value(obj_listbox.value()) # Update it class Dropdown(Widget): @@ -88,5 +86,5 @@ class Dropdown(Widget): def do_sel(self): # Select was pushed if len(self.elements) > 1: - args = (self.writer, self.row - 2, self.col - 2, self, self.textwidth) + args = (self.writer, self.row - 2, self.col - 2, self) Screen.change(_ListDialog, args = args) diff --git a/gui/widgets/menu.py b/gui/widgets/menu.py new file mode 100644 index 0000000..fd901b2 --- /dev/null +++ b/gui/widgets/menu.py @@ -0,0 +1,66 @@ +# menu.py Extension to micro-gui providing the Menu class + +# Released under the MIT License (MIT). See LICENSE. +# Copyright (c) 2021 Peter Hinch + +# Usage: +# from gui.widgets.menu import Menu + +from gui.core.ugui import Window, Screen +from gui.widgets.buttons import Button +from gui.widgets.listbox import Listbox +from gui.core.colors import * + +# Next and Prev close the listbox without running the callback. This is +# handled by Screen .move bound method +# A SubMenu is a Window containing a Listbox +class SubMenu(Window): + + def __init__(self, menu, button, elements, cb, args): # menu is parent Menu + wri = menu.writer + row = 10 + col = button.col + 4 # 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) + 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 + + def callback(self, obj_listbox): + Screen.back() + self.cb(obj_listbox, *self.args) # CB can access obj_listbox.value() or .textvalue() + +class Menu: + + def __init__(self, writer, *, height=25, bgcolor=None, fgcolor=None, textcolor=None, select_color=DARKBLUE, args): # ((text, cb, (args,)),(text, cb, (args,), (elements,)), ...) + self.writer = writer + self.select_color = select_color + row = 2 + col = 2 + btn = {'bgcolor' : bgcolor, + 'fgcolor' : fgcolor, + 'height' : height, + 'textcolor' : textcolor, } + for arg in args: + if len(arg) == 4: # Handle submenu + # txt, cb, (cbargs,), (elements,) = arg + b = Button(writer, row, col, text=arg[0], + callback=self.cb, args=arg, **btn) + else: + txt, cb, cbargs = arg + b = Button(writer, row, col, text=txt, + 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) + Screen.change(SubMenu, args = args)