# 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, display
from gui.widgets.buttons import Button
from gui.widgets.listbox import Listbox
from gui.core.colors import *

# A SubMenu is a Window containing a Listbox
# Next and Prev close the listbox without running the callback. This is
# handled by Screen .move bound method
class SubMenu(Window):

    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.
        te = [x[0] for x in elements]  # Text part
        self.elements = elements
        entry_height, lb_height, _, textwidth = Listbox.dimensions(wri, te, None)
        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, draw_border=False)
        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, lbox):
        display.ipdev.adj_mode(False)  # If in 3-button mode, leave adjust mode
        Screen.back()
        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)
            display.ipdev.adj_mode(True)  # If in 3-button mode, go into adjust mode
        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 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):
        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) == 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:
                txt, cb, cbargs = arg
                b = Button(writer, row, col, text=txt,
                           callback=cb, args=cbargs, **btn)
            col = b.mcol

    def cb(self, button, txt, elements):  # Button pushed which calls submenu
        args = (self, button, elements)
        Screen.change(SubMenu, args = args)
        display.ipdev.adj_mode(True)  # If in 3-button mode, go into adjust mode
